├── acos_client ├── v21 │ ├── __init__.py │ ├── vrrp_a │ │ ├── failover.py │ │ ├── __init__.py │ │ ├── interface.py │ │ └── vrrp_global.py │ ├── slb │ │ ├── common.py │ │ ├── template │ │ │ ├── __init__.py │ │ │ ├── template_ssl.py │ │ │ └── persistence.py │ │ ├── port.py │ │ ├── virtual_service.py │ │ ├── class_list.py │ │ ├── __init__.py │ │ ├── member.py │ │ ├── server.py │ │ ├── virtual_server.py │ │ ├── aflex.py │ │ ├── service_group.py │ │ └── hm.py │ ├── config_file.py │ ├── sflow.py │ ├── device_info.py │ ├── dns.py │ ├── ha.py │ ├── license_manager.py │ ├── partition.py │ ├── nat.py │ ├── admin.py │ ├── session.py │ ├── ssl_adapter.py │ ├── action.py │ ├── base.py │ ├── system.py │ └── log.py ├── v30 │ ├── __init__.py │ ├── glm │ │ ├── __init__.py │ │ ├── proxy.py │ │ └── license.py │ ├── vrrpa │ │ ├── __init__.py │ │ ├── blade_params.py │ │ └── vrid.py │ ├── delete │ │ ├── __init__.py │ │ ├── delete.py │ │ └── glm_license.py │ ├── network.py │ ├── ha.py │ ├── slb │ │ ├── template │ │ │ ├── templates.py │ │ │ ├── __init__.py │ │ │ ├── persistence.py │ │ │ └── l7.py │ │ ├── common.py │ │ ├── __init__.py │ │ ├── tcp_proxy.py │ │ ├── aflex_policy.py │ │ ├── port.py │ │ └── server.py │ ├── file │ │ ├── __init__.py │ │ ├── ssl_key.py │ │ └── ssl_cert.py │ ├── overlay │ │ ├── __init__.py │ │ ├── options.py │ │ └── vtep.py │ ├── device_context.py │ ├── system.py │ ├── dns.py │ ├── session.py │ ├── route.py │ ├── sflow.py │ ├── nat.py │ ├── vlan.py │ ├── base.py │ └── partition.py ├── tests │ ├── unit │ │ ├── __init__.py │ │ ├── v21 │ │ │ ├── __init__.py │ │ │ ├── test_high_availability.py │ │ │ ├── test_interfaces.py │ │ │ └── test_system.py │ │ ├── v30 │ │ │ ├── __init__.py │ │ │ ├── test_slb_common.py │ │ │ ├── test_responses.py │ │ │ ├── test_sflow.py │ │ │ ├── test_dns.py │ │ │ ├── test_port.py │ │ │ └── test_slb_aflex.py │ │ ├── test_hash.py │ │ ├── test_client.py │ │ └── test_utils.py │ ├── __init__.py │ ├── client_cert.pem │ ├── server_cert.pem │ ├── client_key.pem │ └── server_key.pem ├── version.py ├── __init__.py ├── hash.py ├── logutils.py ├── utils.py └── errors.py ├── MANIFEST.in ├── requirements.txt ├── test-requirements.txt ├── .editorconfig ├── TODO.md ├── .travis.yml ├── .gitignore ├── CHANGELOG ├── tox.ini ├── setup.py └── README.md /acos_client/v21/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acos_client/v30/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acos_client/v30/glm/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acos_client/v30/vrrpa/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acos_client/tests/unit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v21/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v30/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /acos_client/v30/delete/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include LICENSE 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests>=2.3.0 2 | six 3 | uhashring==1.2 4 | ipaddress==1.0.22; python_version < '3.0' 5 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | hacking>=0.10,<0.11 2 | mock>=1.0.1; python_version < '3.0' 3 | unittest2; python_version < '3.0' 4 | responses>=0.10.2 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | charset = utf-8 12 | tab_width = 4 13 | # Width of Github's online editor/diff display 14 | max_line_length = 119 15 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | - [ ] Fill out the rest of axapi 2.1 apis 2 | - [ ] Validate more args to methods 3 | - [ ] ACOS 4.0 support 4 | - [ ] SSH as interface support 5 | - [ ] Support stripe-api-object like model; reference object fields as attributes, then save(). 6 | - [ ] Include pdf/html docs to actual REST api. 7 | - [ ] Include ACOS error code/msg string with ACOSException 8 | - [ ] 2.7.1 & partitions 9 | - [ ] python3 support (requires workaround for httplib) 10 | - [ ] py26 tests pass by hand, but not in tox 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | matrix: 3 | include: 4 | - name: "2.7 Unit Tests" 5 | python: "2.7" 6 | env: TOX_ENV=py27 7 | - name: "PyPy Unit Tests" 8 | python: "pypy" 9 | env: TOX_ENV=pypy 10 | - name: "3.4 Unit Tests" 11 | python: "3.4" 12 | env: TOX_ENV=py34 13 | - name: "3.5 Unit Tests" 14 | python: "3.5" 15 | env: TOX_ENV=py35 16 | - name: "3.6 Unit Tests" 17 | python: "3.6" 18 | env: TOX_ENV=py36 19 | - name: "PyPy3 Unit Tests" 20 | python: "pypy3.5" 21 | env: TOX_ENV=pypy3 22 | - name: "Pep8 tests using Flake8" 23 | python: "3.6" 24 | env: TOX_ENV=pep8 25 | install: 26 | - pip install tox 27 | script: 28 | - tox -e $TOX_ENV 29 | -------------------------------------------------------------------------------- /acos_client/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | VERSION = '2.10.0' 16 | -------------------------------------------------------------------------------- /acos_client/v30/network.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015, A10 Networks 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | 19 | 20 | class Network(base.BaseV30): 21 | pass 22 | -------------------------------------------------------------------------------- /acos_client/v21/vrrp_a/failover.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | 19 | 20 | class VRRPAFailoverPolicy(base.BaseV21): 21 | pass 22 | -------------------------------------------------------------------------------- /acos_client/v21/slb/common.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014-2016 A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | 19 | 20 | class SLBCommon(base.BaseV21): 21 | raise NotImplementedError("slb.common support is not available using AXAPI v2.1") 22 | -------------------------------------------------------------------------------- /acos_client/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | # flake8: noqa 15 | 16 | from acos_client.version import VERSION 17 | from acos_client.client import Client 18 | from acos_client.hash import Hash 19 | 20 | AXAPI_21 = '21' 21 | AXAPI_30 = '30' 22 | #AXAPI_SSH = 'ssh' 23 | AXAPI_VERSIONS = (AXAPI_21, AXAPI_30) 24 | -------------------------------------------------------------------------------- /acos_client/v30/ha.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015, A10 Networks 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | 19 | 20 | class HA(base.BaseV30): 21 | 22 | def sync(self, destination_ip, username, password, **kwargs): 23 | raise NotImplemented() 24 | -------------------------------------------------------------------------------- /acos_client/v30/slb/template/templates.py: -------------------------------------------------------------------------------- 1 | # Copyright 2020, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from acos_client.v30 import base 16 | 17 | 18 | class BaseTemplate(base.BaseV30): 19 | 20 | def get(self, **kwargs): 21 | return self._get(self.url_prefix, **kwargs) 22 | 23 | 24 | class Templates(BaseTemplate): 25 | url_prefix = '/slb/template/' 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | bin/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | .python-version 25 | 26 | # Installer logs 27 | pip-log.txt 28 | pip-delete-this-directory.txt 29 | 30 | # Unit test / coverage reports 31 | htmlcov/ 32 | .tox/ 33 | .coverage 34 | .cache 35 | nosetests.xml 36 | coverage.xml 37 | 38 | # Translations 39 | *.mo 40 | 41 | # Mr Developer 42 | .mr.developer.cfg 43 | .project 44 | .pydevproject 45 | .idea 46 | 47 | # Rope 48 | .ropeproject 49 | 50 | # Django stuff: 51 | *.log 52 | *.pot 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | *~ 58 | .DS_Store 59 | .venv/ 60 | *.py[cod] 61 | *.so 62 | .installed.cfg 63 | Vagrantfile 64 | .vagrant/ 65 | tags 66 | 67 | # vi tmp files 68 | *.swp 69 | -------------------------------------------------------------------------------- /acos_client/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2018, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import os 16 | 17 | try: 18 | import unittest2 as unittest 19 | except ImportError: 20 | import unittest 21 | 22 | 23 | def test_suite(): 24 | os.environ.setdefault("PYTHONDONTWRITEBYTECODE", "1") 25 | test_loader = unittest.TestLoader() 26 | test_suite = test_loader.discover("acos_client.tests") 27 | return test_suite 28 | -------------------------------------------------------------------------------- /acos_client/v30/delete/delete.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | from acos_client.v30.delete import glm_license 19 | 20 | 21 | class Delete(base.BaseV30): 22 | 23 | @property 24 | def glm_license(self): 25 | return glm_license.DeleteGLMLicense(self.client) 26 | -------------------------------------------------------------------------------- /acos_client/v30/file/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015, Tobit Raff, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import acos_client.v30.base as base 16 | 17 | from acos_client.v30.file.ssl_cert import SSLCert 18 | from acos_client.v30.file.ssl_key import SSLKey 19 | 20 | 21 | class File(base.BaseV30): 22 | @property 23 | def ssl_cert(self): 24 | return SSLCert(self.client) 25 | 26 | @property 27 | def ssl_key(self): 28 | return SSLKey(self.client) 29 | -------------------------------------------------------------------------------- /acos_client/hash.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import uhashring 18 | 19 | 20 | class Hash(object): 21 | 22 | def __init__(self, server_list): 23 | self.server_list = server_list 24 | self.ring = uhashring.HashRing(self.server_list) 25 | 26 | def get_server(self, unique_token): 27 | return self.ring.get_node(unique_token) 28 | -------------------------------------------------------------------------------- /acos_client/v30/overlay/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014-2016 A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import acos_client.v30.base as base 16 | 17 | from acos_client.v30.overlay.options import OverlayOptions 18 | from acos_client.v30.overlay.vtep import OverlayVtep 19 | 20 | 21 | class Overlay(base.BaseV30): 22 | @property 23 | def options(self): 24 | return OverlayOptions(self.client) 25 | 26 | @property 27 | def vtep(self): 28 | return OverlayVtep(self.client) 29 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | --------------------------- 2 | acos-client CHANGELOG 3 | --------------------------- 4 | 5 | acos-client. Changes tracked from 1.4.2 > onward 6 | * 1.4.7 7 | - Added IPv6 support for aXAPI v21 and v30 as well as IPv6 test cases 8 | - Updated ACOS response messages 9 | - IPv6 enhancements to t.py 10 | - Improved t.py error handling and better support for aXAPI v2.1 11 | 12 | 13 | * 1.4.6 14 | - Fixed duplicate SG creation bug. 15 | 16 | * 1.4.5 17 | - Fixed arp-disable defaulting to true when present in payload 18 | - Improved unit test coverage for SLB modules 19 | - Usage of responses library for mocking client 20 | 21 | 22 | * 1.4.4 23 | - Adds VLAN, VE/LIF interfaces, VTEP support for AXAPI v3.0 24 | - VRRP-A support for AXAPI v3.0 25 | - Enhanced error handling for DHCP offer failures 26 | - Added linebreaks to this file between versions to make it more readable. 27 | 28 | * 1.4.3 29 | - Ensure passing of port and correct param name for HM port override 30 | 31 | * 1.4.2 32 | - Checks for name-based configuration elements to ensure other business rules do not override configured defaults 33 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py{27,py,34,35,36,py3},pep8 8 | 9 | [testenv] 10 | setenv = 11 | PYTHONDONTWRITEBYTECODE=1 12 | PYTHONHASHSEED=42 13 | VIRTUAL_ENV={envdir} 14 | usedevelop = True 15 | install_command = pip install -U {opts} {packages} 16 | deps = 17 | -r{toxinidir}/requirements.txt 18 | -r{toxinidir}/test-requirements.txt 19 | commands = python setup.py test -q {posargs} 20 | 21 | [testenv:pep8] 22 | basepython = python3.6 23 | commands = flake8 24 | 25 | # Environment to test pep8 for Openstack py27 support 26 | [testenv:ospep8] 27 | basepython = python2.7 28 | commands = flake8 29 | 30 | [flake8] 31 | #ignore = E122,E125,E126,E128,E129,E251,E265,E713,F402,F811,F812,H104,H237,H302,H304,H305,H307,H401,H402,H404,H405,H904 32 | ignore = H301 33 | show-source = true 34 | exclude = .venv,.git,.tox 35 | max-line-length = 119 36 | -------------------------------------------------------------------------------- /acos_client/tests/unit/test_hash.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | try: 18 | import unittest2 as unittest 19 | except ImportError: 20 | import unittest 21 | 22 | import acos_client 23 | 24 | servers = ['a', 'b', 'c', 'd', 'e', 'f'] 25 | 26 | 27 | class TestHash(unittest.TestCase): 28 | 29 | def test_hash(self): 30 | h = acos_client.Hash(servers) 31 | a = h.get_server('aaa') 32 | h.get_server('bbb') 33 | h.get_server('ccc') 34 | self.assertEqual(a, h.get_server('aaa')) 35 | -------------------------------------------------------------------------------- /acos_client/v21/config_file.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | from acos_client.v21 import base 16 | 17 | 18 | class ConfigFile(base.BaseV21): 19 | 20 | def upload(self, cfg_backup, **kwargs): 21 | return self._post("system.config_file.upload", cfg_backup, **kwargs) 22 | 23 | def restore(self, **kwargs): 24 | return self._post("system.config_file.restore", **kwargs) 25 | 26 | def write(self, from_file, to_file, **kwargs): 27 | return self._post("system.config_file.write", 28 | {"from": from_file, "to": to_file}, **kwargs) 29 | -------------------------------------------------------------------------------- /acos_client/v21/sflow.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016, A10 Networks, All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | 19 | 20 | class SFlow(base.BaseV30): 21 | 22 | url_prefix = '/sflow/' 23 | 24 | @property 25 | def collector(self): 26 | raise NotImplementedError("Not implemented in API v2.1") 27 | 28 | @property 29 | def setting(self): 30 | raise NotImplementedError("Not implemented in API v2.1") 31 | 32 | @property 33 | def polling(self): 34 | raise NotImplementedError("Not implemented in API v2.1") 35 | -------------------------------------------------------------------------------- /acos_client/v21/device_info.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | from acos_client.v21 import base 16 | 17 | 18 | class DeviceInfo(base.BaseV21): 19 | 20 | def get(self, **kwargs): 21 | return self._get('system.device_info.get', **kwargs) 22 | 23 | def cpu_current_usage(self, **kwargs): 24 | return self._get('system.device_info.cpu.current_usage.get', 25 | **kwargs) 26 | 27 | def cpu_historical_usage(self, **kwargs): 28 | return self._get('system.device_info.cpu.historical_usage.get', 29 | **kwargs) 30 | -------------------------------------------------------------------------------- /acos_client/v30/slb/common.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014-2016 A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import six 18 | 19 | from acos_client.v30 import base 20 | 21 | 22 | class SLBCommon(base.BaseV30): 23 | 24 | url_prefix = "/slb/common" 25 | 26 | def _underscore_to_dash(self, val): 27 | rv = val.replace("_", "-") 28 | return rv 29 | 30 | def create(self, **kwargs): 31 | params = {"common": {}} 32 | for k, v in six.iteritems(kwargs): 33 | params["common"][self._underscore_to_dash(k)] = v 34 | kwargs = {} 35 | 36 | return self._post(self.url_prefix, params, **kwargs) 37 | -------------------------------------------------------------------------------- /acos_client/v21/dns.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | 19 | 20 | class DNS(base.BaseV21): 21 | 22 | def set(self, primary=None, secondary=None, suffix=None, **kwargs): 23 | settings = {} 24 | 25 | if primary is not None: 26 | settings['primary_dns'] = primary 27 | 28 | if secondary is not None: 29 | settings['secondary_dns'] = secondary 30 | 31 | if suffix is not None: 32 | settings['dns_suffix'] = suffix 33 | 34 | payload = {'dns': settings} 35 | 36 | return self._post("network.dns.server.set", payload, **kwargs) 37 | -------------------------------------------------------------------------------- /acos_client/v30/device_context.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015, A10 Networks 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | 19 | 20 | class DeviceContext(base.BaseV30): 21 | """Switching of device-contexts""" 22 | url_prefix = "/device-context" 23 | 24 | def switch(self, device_id, obj_slot_id): 25 | """Switching of device-context""" 26 | payload = { 27 | "device-context": self._build_payload(device_id, obj_slot_id) 28 | } 29 | 30 | return self._post(self.url_prefix, payload) 31 | 32 | def _build_payload(self, device_id, obj_slot_id): 33 | 34 | payload = { 35 | "device-id": device_id 36 | } 37 | 38 | return payload 39 | -------------------------------------------------------------------------------- /acos_client/v21/vrrp_a/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import unicode_literals 17 | 18 | import acos_client.v21.base as base 19 | 20 | from acos_client.v21.vrrp_a.failover import VRRPAFailoverPolicy 21 | from acos_client.v21.vrrp_a.interface import VRRPAInterface 22 | from acos_client.v21.vrrp_a.vrrp_global import VRRPAGlobal 23 | 24 | 25 | class VRRPA(base.BaseV21): 26 | # For status args 27 | @property 28 | def vrrpa_global(self): 29 | return VRRPAGlobal(self.client) 30 | 31 | @property 32 | def interface(self): 33 | return VRRPAInterface(self.client) 34 | 35 | @property 36 | def failover_policy(self): 37 | return VRRPAFailoverPolicy(self.client) 38 | -------------------------------------------------------------------------------- /acos_client/logutils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016, All Rights Reserved, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import six 16 | 17 | CLEAN_FIELDS = ["username", "password"] 18 | 19 | REPLACEMENT = "*" * 8 20 | 21 | 22 | def clean(data, field=None): 23 | if field in CLEAN_FIELDS: 24 | return REPLACEMENT 25 | 26 | # Mocks are gross and they don't live in production code. 27 | # We can ignore them. 28 | if type(data).__module__ == 'mock.mock': 29 | return data 30 | 31 | if type(data) is dict: 32 | return type(data)( 33 | (x, clean(y, field=x)) for x, y in six.iteritems(data) 34 | ) 35 | elif isinstance(data, six.string_types): 36 | return data 37 | elif isinstance(data, (list, tuple)): 38 | return type(data)(clean(x) for x in data) 39 | 40 | return data 41 | -------------------------------------------------------------------------------- /acos_client/v21/ha.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | 19 | 20 | class HA(base.BaseV21): 21 | 22 | def sync(self, destination_ip, username, password): 23 | params = { 24 | "ha_config_sync": { 25 | "auto_authentication": 0, 26 | "user": username, 27 | "password": password, 28 | "sync_all_partition": 1, 29 | "operation": 2, # running config only 30 | "peer_operation": 0, # running config 31 | "peer_reload": 0, 32 | "destination_ip": destination_ip 33 | } 34 | } 35 | 36 | self._post('ha.sync_config', params) 37 | -------------------------------------------------------------------------------- /acos_client/v30/system.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30.action import Action 18 | from acos_client.v30 import base 19 | from acos_client.v30.partition import Partition 20 | 21 | 22 | class System(base.BaseV30): 23 | 24 | @property 25 | def action(self): 26 | return Action(self.client) 27 | 28 | @property 29 | def partition(self): 30 | return Partition(self.client) 31 | 32 | def information(self): 33 | return self._get("/system") 34 | 35 | def stats(self, name='', max_retries=None, timeout=None, **kwargs): 36 | return self._get("/system/" + name + '/stats', 37 | max_retries=max_retries, timeout=timeout, 38 | **kwargs) 39 | -------------------------------------------------------------------------------- /acos_client/v21/slb/template/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import acos_client.v21.base as base 16 | 17 | from acos_client.v21.slb.template.persistence import CookiePersistence 18 | from acos_client.v21.slb.template.persistence import SourceIpPersistence 19 | from acos_client.v21.slb.template.template_ssl import ClientSSL 20 | from acos_client.v21.slb.template.template_ssl import ServerSSL 21 | 22 | 23 | class Template(base.BaseV21): 24 | 25 | @property 26 | def client_ssl(self): 27 | return ClientSSL(self.client) 28 | 29 | @property 30 | def server_ssl(self): 31 | return ServerSSL(self.client) 32 | 33 | @property 34 | def cookie_persistence(self): 35 | return CookiePersistence(self.client) 36 | 37 | @property 38 | def src_ip_persistence(self): 39 | return SourceIpPersistence(self.client) 40 | -------------------------------------------------------------------------------- /acos_client/tests/client_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID7TCCAtWgAwIBAgIJAMJp9+T1qxi6MA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD 3 | VQQGEwJVUzETMBEGA1UECAwKU29tZS1TdGF0ZTEPMA0GA1UEBwwGTXl0b3duMSMw 4 | IQYDVQQKDBpBMTAgQUNPUyBTbW9rZSBUZXN0aW5nIExMQzEYMBYGA1UECwwPbWFr 5 | ZWl0YnJlYWsuY29tMRgwFgYDVQQDDA9tYWtlaXRicmVhay5jb20wHhcNMTYwNjIz 6 | MjAzMDUxWhcNMjYwNjIxMjAzMDUxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgM 7 | ClNvbWUtU3RhdGUxDzANBgNVBAcMBk15dG93bjEjMCEGA1UECgwaQTEwIEFDT1Mg 8 | U21va2UgVGVzdGluZyBMTEMxGDAWBgNVBAsMD21ha2VpdGJyZWFrLmNvbTEYMBYG 9 | A1UEAwwPbWFrZWl0YnJlYWsuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 10 | CgKCAQEAoxRqwJP/aPr+NCBB25MdCXaYlW4z1QuBNzt293F/M65Yox7y8ZUl6/3s 11 | CUY6+sJw86M/bSD9IqqyFXRtfryw936C4oMFlDcGBYPlNU/sD0IP7xrFTlc7uyrx 12 | vCkEZQPZweUmZzmm3TojF/R5XDaoe6w1VYa0THU2FlkwGZ7MEQavWASHOx4AbqeP 13 | dU/Y9pWFIex/Lm3BFJIg7YpHj9xi0A/6F14njoLuyiUCFqRYIzh2/hsFNjQsKJ6I 14 | mlRYetXgdg8N4ePwvhT0auFUbUAKhVphx1UxH9npH0TER83yYlla9poG1C9Q26Zo 15 | ZR7UV8VccUwtyxMmEQ/0Vwr4/f3pmwIDAQABo1AwTjAdBgNVHQ4EFgQUoixcd+zs 16 | x3TZqmYoB/PK6d7oDnwwHwYDVR0jBBgwFoAUoixcd+zsx3TZqmYoB/PK6d7oDnww 17 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAfd7kSWL85SW1txUOd5Nq 18 | ZGTL0XUEc31TJ/w9uCkifixSxjQSR6HxsqIDIzyQUFmf5xXV1llwAlvqvZICTh/O 19 | //u0WN8fEucz5WXmeBGDjS8+tKcdlPwREwM+ryMk42KjojD8s4+CokCcyXIqexIL 20 | zfbhvR6SD1D78bPxYE9Qa1DTaz9DbLYxKHl4L9VfRQuhkvUVFzp1exsqmp1mOXUw 21 | Fqbhx3Kb243OjPT9HC/a8FHElNXzZtiGu6JiYQyDJWdKdxOZ+Bd9O07i4eKY0Zpf 22 | knvq8XtppHsYJ6oGmWJXN42ZUJfHZhJIG5Sfd6ecRzW7KIcXD5pRSMUyUBB2T8g8 23 | mQ== 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /acos_client/tests/server_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID7TCCAtWgAwIBAgIJAMJp9+T1qxi6MA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD 3 | VQQGEwJVUzETMBEGA1UECAwKU29tZS1TdGF0ZTEPMA0GA1UEBwwGTXl0b3duMSMw 4 | IQYDVQQKDBpBMTAgQUNPUyBTbW9rZSBUZXN0aW5nIExMQzEYMBYGA1UECwwPbWFr 5 | ZWl0YnJlYWsuY29tMRgwFgYDVQQDDA9tYWtlaXRicmVhay5jb20wHhcNMTYwNjIz 6 | MjAzMDUxWhcNMjYwNjIxMjAzMDUxWjCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgM 7 | ClNvbWUtU3RhdGUxDzANBgNVBAcMBk15dG93bjEjMCEGA1UECgwaQTEwIEFDT1Mg 8 | U21va2UgVGVzdGluZyBMTEMxGDAWBgNVBAsMD21ha2VpdGJyZWFrLmNvbTEYMBYG 9 | A1UEAwwPbWFrZWl0YnJlYWsuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 10 | CgKCAQEAoxRqwJP/aPr+NCBB25MdCXaYlW4z1QuBNzt293F/M65Yox7y8ZUl6/3s 11 | CUY6+sJw86M/bSD9IqqyFXRtfryw936C4oMFlDcGBYPlNU/sD0IP7xrFTlc7uyrx 12 | vCkEZQPZweUmZzmm3TojF/R5XDaoe6w1VYa0THU2FlkwGZ7MEQavWASHOx4AbqeP 13 | dU/Y9pWFIex/Lm3BFJIg7YpHj9xi0A/6F14njoLuyiUCFqRYIzh2/hsFNjQsKJ6I 14 | mlRYetXgdg8N4ePwvhT0auFUbUAKhVphx1UxH9npH0TER83yYlla9poG1C9Q26Zo 15 | ZR7UV8VccUwtyxMmEQ/0Vwr4/f3pmwIDAQABo1AwTjAdBgNVHQ4EFgQUoixcd+zs 16 | x3TZqmYoB/PK6d7oDnwwHwYDVR0jBBgwFoAUoixcd+zsx3TZqmYoB/PK6d7oDnww 17 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAfd7kSWL85SW1txUOd5Nq 18 | ZGTL0XUEc31TJ/w9uCkifixSxjQSR6HxsqIDIzyQUFmf5xXV1llwAlvqvZICTh/O 19 | //u0WN8fEucz5WXmeBGDjS8+tKcdlPwREwM+ryMk42KjojD8s4+CokCcyXIqexIL 20 | zfbhvR6SD1D78bPxYE9Qa1DTaz9DbLYxKHl4L9VfRQuhkvUVFzp1exsqmp1mOXUw 21 | Fqbhx3Kb243OjPT9HC/a8FHElNXzZtiGu6JiYQyDJWdKdxOZ+Bd9O07i4eKY0Zpf 22 | knvq8XtppHsYJ6oGmWJXN42ZUJfHZhJIG5Sfd6ecRzW7KIcXD5pRSMUyUBB2T8g8 23 | mQ== 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /acos_client/v30/delete/glm_license.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | 19 | 20 | class DeleteGLMLicense(base.BaseV30): 21 | url_prefix = '/delete/glm-license/' 22 | 23 | def post(self, a10_ti=None, ipsec_vpn=None, qosmos=None, 24 | threatstop=None, webroot=None, webroot_ti=None, 25 | max_retries=None, timeout=None, **kwargs): 26 | params = { 27 | "glm-license": self.minimal_dict({ 28 | "a10-ti": a10_ti, 29 | "ipsec-vpn": ipsec_vpn, 30 | "qosmos": qosmos, 31 | "threatstop": threatstop, 32 | "webroot": webroot, 33 | "webroot-ti": webroot_ti 34 | }), 35 | } 36 | 37 | if not params['glm-license']: 38 | params = {} 39 | 40 | self._post(self.url_prefix, params, max_retries=max_retries, 41 | timeout=timeout, axapi_args=kwargs) 42 | -------------------------------------------------------------------------------- /acos_client/v21/license_manager.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | 19 | 20 | class LicenseManager(base.BaseV21): 21 | """v2.1 LicenseManager is not yet supported""" 22 | def create(self, host_list=[], serial=None, instance_name=None, use_mgmt_port=False, 23 | interval=None, bandwidth_base=None, bandwidth_unrestricted=None): 24 | raise NotImplementedError("LicenseManager is not yet supported using AXAPI v2.1") 25 | 26 | def get(self): 27 | raise NotImplementedError("LicenseManager is not yet supported using AXAPI v2.1") 28 | 29 | def connect(self, connect=False): 30 | raise NotImplementedError("LicenseManager is not yet supported using AXAPI v2.1") 31 | 32 | def update(self, host_list=[], serial=None, instance_name=None, use_mgmt_port=False, 33 | interval=None, bandwidth_base=None, bandwidth_unrestricted=None): 34 | raise NotImplementedError("LicenseManager is not yet supported using AXAPI v2.1") 35 | -------------------------------------------------------------------------------- /acos_client/tests/client_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCjFGrAk/9o+v40 3 | IEHbkx0JdpiVbjPVC4E3O3b3cX8zrlijHvLxlSXr/ewJRjr6wnDzoz9tIP0iqrIV 4 | dG1+vLD3foLigwWUNwYFg+U1T+wPQg/vGsVOVzu7KvG8KQRlA9nB5SZnOabdOiMX 5 | 9HlcNqh7rDVVhrRMdTYWWTAZnswRBq9YBIc7HgBup491T9j2lYUh7H8ubcEUkiDt 6 | ikeP3GLQD/oXXieOgu7KJQIWpFgjOHb+GwU2NCwonoiaVFh61eB2Dw3h4/C+FPRq 7 | 4VRtQAqFWmHHVTEf2ekfRMRHzfJiWVr2mgbUL1DbpmhlHtRXxVxxTC3LEyYRD/RX 8 | Cvj9/embAgMBAAECggEAYod3aBsC+b6Lz5qdr7hWlt0cm0wV7OYij+hRnHbqT6NK 9 | 0mNkjSl72/VyorfX8qF/9PPw4lJIHqXbKrNJZIVEtoOtOIXI3R/Rd4uU9HzxNtbH 10 | IcOe6hIyeIcdvn1Ztl55Nnjolv1yH798bIC8wkYTzYTiRGY6kOdQYnhIY3JaAP59 11 | wOTMTYW3+81DH6qMb6fi/8CDRhFv8nY/P2edyxUA44cgsUT8wWMj9mcpO5z6Bece 12 | F6IpbegO1PlybLAB4zNhZAJ0R7RYBmaYT3rBcghJIIXpUn0gug+ZlrmSPeKN7qNW 13 | 5a8pNigUuOl9mOBtksa194tiPzQU6wTg7c0tR1mOIQKBgQDXD/02PJkrCTmsNokv 14 | x5PrUSMCVxZpuzlIe/U0wZdtS1lP10YZNHIpRVgNlQ/QV/9CH8s+ghux0FevgO98 15 | gGOuJqWfKKNcbpD9S8kg7ZaWfzUNc6OTIyyuQ1r7IOyziyriFg6AH334CaRnqE2Z 16 | DbnW2nBcCmp1ATvngdBv8kwQFQKBgQDCH056icSzdNw+jht8JSAMVM/HOib3vaYB 17 | FjjYPREHq2bbIB5hA8RySZWJcuByxqN+/qLwXY3vSFGO95qBL0xU99jJ+U5xVBoS 18 | cX6NxmgvW3fXLpfQDz4vJ51INiIAyrVNcxZN9TVFrTgJXCKTOPLsS56lYkbBJz84 19 | IhMTvGLO7wKBgQCtiNdXNlqZoV4KGg9koHQ5Q0UulDsfodU9KdjYcwXPSSeOBzUn 20 | DWy45J2CiC80fG0aXDFSBQZ32peGpFGacrb8RW8LGG2JHiacXNS0X0JNueODMTZi 21 | edWJ4Au/6/dTgQ5fVFDrDX5F8PHaOrIyuCKmvahAfJ8ePpqp2dPpIOhDaQKBgQCD 22 | uuztmLnjscSXqqWaHDNgStlo79xrt8WD7UmL6/y3gKfewS/8U6smhyqzyEHpgUSH 23 | tFJr3ICpxSCbbQjq62bYLgxuGwERRKogo+XmXaJrqJ1tZ4/bv8xKAY7o5tsyQFzB 24 | /vw+0MxiyQZCy8QmtbmbgkFZJ5SuFG0BMZZSiT9f/wKBgQCle6+GgOF1yKzGIhwK 25 | salYyZk+weKg7UXQlU1YJJwDGIyE2WWd8AEt1n3f7ZsO28ZbYlLLgGKVQQQ/o+ek 26 | hIyMvjOJT34IzGSELe2s8B+pDBFDc7ubFp/vpzejasK/b+aHUWFzBHoBVxnyyGSH 27 | DTUXtvne6nwV/RngzQjqeH9/lg== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /acos_client/tests/server_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCjFGrAk/9o+v40 3 | IEHbkx0JdpiVbjPVC4E3O3b3cX8zrlijHvLxlSXr/ewJRjr6wnDzoz9tIP0iqrIV 4 | dG1+vLD3foLigwWUNwYFg+U1T+wPQg/vGsVOVzu7KvG8KQRlA9nB5SZnOabdOiMX 5 | 9HlcNqh7rDVVhrRMdTYWWTAZnswRBq9YBIc7HgBup491T9j2lYUh7H8ubcEUkiDt 6 | ikeP3GLQD/oXXieOgu7KJQIWpFgjOHb+GwU2NCwonoiaVFh61eB2Dw3h4/C+FPRq 7 | 4VRtQAqFWmHHVTEf2ekfRMRHzfJiWVr2mgbUL1DbpmhlHtRXxVxxTC3LEyYRD/RX 8 | Cvj9/embAgMBAAECggEAYod3aBsC+b6Lz5qdr7hWlt0cm0wV7OYij+hRnHbqT6NK 9 | 0mNkjSl72/VyorfX8qF/9PPw4lJIHqXbKrNJZIVEtoOtOIXI3R/Rd4uU9HzxNtbH 10 | IcOe6hIyeIcdvn1Ztl55Nnjolv1yH798bIC8wkYTzYTiRGY6kOdQYnhIY3JaAP59 11 | wOTMTYW3+81DH6qMb6fi/8CDRhFv8nY/P2edyxUA44cgsUT8wWMj9mcpO5z6Bece 12 | F6IpbegO1PlybLAB4zNhZAJ0R7RYBmaYT3rBcghJIIXpUn0gug+ZlrmSPeKN7qNW 13 | 5a8pNigUuOl9mOBtksa194tiPzQU6wTg7c0tR1mOIQKBgQDXD/02PJkrCTmsNokv 14 | x5PrUSMCVxZpuzlIe/U0wZdtS1lP10YZNHIpRVgNlQ/QV/9CH8s+ghux0FevgO98 15 | gGOuJqWfKKNcbpD9S8kg7ZaWfzUNc6OTIyyuQ1r7IOyziyriFg6AH334CaRnqE2Z 16 | DbnW2nBcCmp1ATvngdBv8kwQFQKBgQDCH056icSzdNw+jht8JSAMVM/HOib3vaYB 17 | FjjYPREHq2bbIB5hA8RySZWJcuByxqN+/qLwXY3vSFGO95qBL0xU99jJ+U5xVBoS 18 | cX6NxmgvW3fXLpfQDz4vJ51INiIAyrVNcxZN9TVFrTgJXCKTOPLsS56lYkbBJz84 19 | IhMTvGLO7wKBgQCtiNdXNlqZoV4KGg9koHQ5Q0UulDsfodU9KdjYcwXPSSeOBzUn 20 | DWy45J2CiC80fG0aXDFSBQZ32peGpFGacrb8RW8LGG2JHiacXNS0X0JNueODMTZi 21 | edWJ4Au/6/dTgQ5fVFDrDX5F8PHaOrIyuCKmvahAfJ8ePpqp2dPpIOhDaQKBgQCD 22 | uuztmLnjscSXqqWaHDNgStlo79xrt8WD7UmL6/y3gKfewS/8U6smhyqzyEHpgUSH 23 | tFJr3ICpxSCbbQjq62bYLgxuGwERRKogo+XmXaJrqJ1tZ4/bv8xKAY7o5tsyQFzB 24 | /vw+0MxiyQZCy8QmtbmbgkFZJ5SuFG0BMZZSiT9f/wKBgQCle6+GgOF1yKzGIhwK 25 | salYyZk+weKg7UXQlU1YJJwDGIyE2WWd8AEt1n3f7ZsO28ZbYlLLgGKVQQQ/o+ek 26 | hIyMvjOJT34IzGSELe2s8B+pDBFDc7ubFp/vpzejasK/b+aHUWFzBHoBVxnyyGSH 27 | DTUXtvne6nwV/RngzQjqeH9/lg== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /acos_client/v21/vrrp_a/interface.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | 19 | 20 | class VRRPAInterface(base.BaseV21): 21 | def get_all(self, **kwargs): 22 | return self._get("vrrp_a.interface.getAll", **kwargs) 23 | 24 | def search(self, interface_num): 25 | params = {"interface_number": interface_num} 26 | 27 | return self._post("vrrp_a.interface.search", params) 28 | 29 | def update(self, interface_number, interface_type, status, vrrp_a_status, link_type, heartbeat, vlan=None): 30 | env_val = "vrrp_a_interface" 31 | params = { 32 | env_val: { 33 | "interface_number": interface_number, 34 | "interface_type": interface_type, 35 | "status": status, 36 | "vrrp_a_status": vrrp_a_status, 37 | "link_type": link_type, 38 | "heartbeat": heartbeat 39 | } 40 | } 41 | 42 | if vlan: 43 | params[env_val]["vlan"] = vlan 44 | 45 | return self._post("vrrp_a.interface.update", params) 46 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v30/test_slb_common.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014-2016, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | try: 18 | import unittest 19 | from unittest import mock 20 | except ImportError: 21 | import mock 22 | import unittest2 as unittest 23 | 24 | from acos_client.v30.slb import common 25 | 26 | 27 | class TestSFlow(unittest.TestCase): 28 | def setUp(self): 29 | self.client = mock.MagicMock() 30 | self.target = common.SLBCommon(self.client) 31 | 32 | def test_underscore_to_dash(self): 33 | expected = "no-dsr-health-check" 34 | actual = self.target._underscore_to_dash(expected) 35 | self.assertEqual(expected.replace('_', '-'), actual) 36 | 37 | def test_create(self): 38 | in_params = {"no_dsr_health_check": 1, "nounderscores": "string", "boolean": False} 39 | expected_params = {"no-dsr-health-check": 1, "nounderscores": "string", "boolean": False} 40 | self.target.create(**in_params) 41 | ((method, url, params, header), kwargs) = self.client.http.request.call_args 42 | self.assertTrue('GET', method) 43 | self.assertTrue('/axapi/v3/' + self.target.url_prefix, url) 44 | self.assertTrue(expected_params, params) 45 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v21/test_high_availability.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import unicode_literals 17 | 18 | try: 19 | import unittest2 as unittest 20 | except ImportError: 21 | import unittest 22 | 23 | from acos_client import client 24 | import responses 25 | 26 | 27 | HOSTNAME = 'fake_a10' 28 | BASE_URL = "https://{}:443/services/rest/v2.1/?format=json&method=".format(HOSTNAME) 29 | AUTH_URL = "{}authenticate".format(BASE_URL) 30 | HA_URL = '{}ha.sync_config&session_id={}'.format(BASE_URL, 'foobar') 31 | 32 | 33 | class TestHighAvailability(unittest.TestCase): 34 | 35 | def setUp(self): 36 | self.client = client.Client(HOSTNAME, '21', 'fake_username', 'fake_password') 37 | 38 | @responses.activate 39 | def test_high_availability_sync(self): 40 | responses.add(responses.POST, AUTH_URL, json={'session_id': 'foobar'}) 41 | responses.add(responses.POST, HA_URL) 42 | 43 | resp = self.client.ha.sync('192.168.2.254', 'fake_username', 'fake_password') 44 | 45 | self.assertIsNone(resp) 46 | self.assertEqual(len(responses.calls), 2) 47 | self.assertEqual(responses.calls[1].request.method, responses.POST) 48 | self.assertEqual(responses.calls[1].request.url, HA_URL) 49 | -------------------------------------------------------------------------------- /acos_client/v21/partition.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client import errors as acos_errors 18 | from acos_client.v21 import base 19 | 20 | 21 | class Partition(base.BaseV21): 22 | 23 | def exists(self, name): 24 | if name == 'shared': 25 | return True 26 | try: 27 | self._post("system.partition.search", {'name': name}) 28 | return True 29 | except acos_errors.NotFound: 30 | return False 31 | 32 | def active(self, name='shared'): 33 | if self.client.current_partition != name: 34 | self._post("system.partition.active", {'name': name}) 35 | self.client.current_partition = name 36 | 37 | def create(self, name): 38 | params = { 39 | 'partition': { 40 | 'max_aflex_file': 32, 41 | 'network_partition': 0, 42 | 'name': name 43 | } 44 | } 45 | if name != 'shared': 46 | self._post("system.partition.create", params) 47 | 48 | def delete(self, name): 49 | if name != 'shared': 50 | self.client.session.close() 51 | self._post("system.partition.delete", {"name": name}) 52 | -------------------------------------------------------------------------------- /acos_client/v30/slb/template/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import acos_client.v30.base as base 16 | 17 | from acos_client.v30.slb.template.l7 import HTTPTemplate 18 | from acos_client.v30.slb.template.persistence import CookiePersistence 19 | from acos_client.v30.slb.template.persistence import SourceIpPersistence 20 | from acos_client.v30.slb.template.ssl import ClientSSL 21 | from acos_client.v30.slb.template.ssl import ServerSSL 22 | from acos_client.v30.slb.template.ssl import SSLCipher 23 | from acos_client.v30.slb.template.templates import Templates 24 | 25 | 26 | class Template(base.BaseV30): 27 | 28 | @property 29 | def client_ssl(self): 30 | return ClientSSL(self.client) 31 | 32 | @property 33 | def cipher_ssl(self): 34 | return SSLCipher(self.client) 35 | 36 | @property 37 | def cookie_persistence(self): 38 | return CookiePersistence(self.client) 39 | 40 | @property 41 | def src_ip_persistence(self): 42 | return SourceIpPersistence(self.client) 43 | 44 | @property 45 | def server_ssl(self): 46 | return ServerSSL(self.client) 47 | 48 | @property 49 | def http_template(self): 50 | return HTTPTemplate(self.client) 51 | 52 | @property 53 | def templates(self): 54 | return Templates(self.client) 55 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # flake8: noqa 3 | 4 | from setuptools import find_packages, setup 5 | from os import path 6 | 7 | this_directory = path.abspath(path.dirname(__file__)) 8 | try: 9 | with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f: 10 | long_description = f.read() 11 | except TypeError: 12 | with open(path.join(this_directory, 'README.md'), 'rb') as f: 13 | long_description = f.read().decode('utf-8') 14 | 15 | setup( 16 | name = "acos-client", 17 | version = "2.10.0", 18 | packages = find_packages(), 19 | 20 | author = "A10 Networks", 21 | author_email = "opensource@a10networks.com", 22 | description = "A10 Networks ACOS API Client", 23 | license = "Apache", 24 | keywords = "a10 axapi acos adc slb load balancer", 25 | url = "https://github.com/a10networks/acos-client", 26 | long_description = long_description, 27 | long_description_content_type = "text/markdown", 28 | 29 | classifiers = [ 30 | 'Intended Audience :: Developers', 31 | 'License :: OSI Approved :: Apache Software License', 32 | 'Operating System :: MacOS :: MacOS X', 33 | 'Operating System :: POSIX', 34 | 'Programming Language :: Python', 35 | 'Programming Language :: Python :: 2.6', 36 | 'Programming Language :: Python :: 2.7', 37 | 'Programming Language :: Python :: 3.3', 38 | 'Programming Language :: Python :: 3.4', 39 | 'Programming Language :: Python :: 3.5', 40 | 'Programming Language :: Python :: 3.6', 41 | "Programming Language :: Python :: Implementation :: CPython", 42 | "Programming Language :: Python :: Implementation :: PyPy", 43 | 'Topic :: Internet', 44 | 'Topic :: Software Development :: Libraries :: Python Modules' 45 | ], 46 | 47 | install_requires = ['requests>=2.3.0', 'six', 'uhashring'], 48 | 49 | test_suite="acos_client.tests.test_suite" 50 | ) 51 | -------------------------------------------------------------------------------- /acos_client/v21/slb/port.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | from acos_client.v21 import base 16 | 17 | 18 | class Port(base.BaseV21): 19 | 20 | # Protocols 21 | TCP = 2 22 | UDP = 3 23 | 24 | def _set(self, action, name, port_num, protocol, **kwargs): 25 | 26 | params = { 27 | "name": name, 28 | "port": { 29 | "port_num": port_num, 30 | "protocol": protocol, 31 | } 32 | } 33 | 34 | return self._post(action, params, **kwargs) 35 | 36 | def create(self, name, port_num, protocol, **kwargs): 37 | return self._set("slb.server.port.create", name, port_num, protocol, 38 | **kwargs) 39 | 40 | def update(self, name, port_num, protocol, **kwargs): 41 | return self._set("slb.server.port.update", name, port_num, protocol, 42 | **kwargs) 43 | 44 | def all_update(self, name, port_num, protocol, **kwargs): 45 | return self._set("slb.server.port.updateAll", name, port_num, protocol, 46 | **kwargs) 47 | 48 | def delete(self, name, port_num, protocol, **kwargs): 49 | self._set("slb.server.port.delete", name, port_num, protocol, **kwargs) 50 | 51 | def all_delete(self, name, **kwargs): 52 | self._get("slb.server.port.deleteAll", {"name": name}, **kwargs) 53 | -------------------------------------------------------------------------------- /acos_client/v30/slb/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014-2016 A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import acos_client.v30.base as base 16 | 17 | from acos_client.v30.slb.aflex_policy import AFlexPolicy 18 | from acos_client.v30.slb.common import SLBCommon 19 | from acos_client.v30.slb.hm import HealthMonitor 20 | from acos_client.v30.slb.server import Server 21 | from acos_client.v30.slb.service_group import ServiceGroup 22 | from acos_client.v30.slb.template import Template 23 | from acos_client.v30.slb.tcp_proxy import TcpProxy 24 | from acos_client.v30.slb.virtual_server import VirtualServer 25 | 26 | 27 | class SLB(base.BaseV30): 28 | # For status args 29 | DOWN = 0 30 | UP = 1 31 | 32 | @property 33 | def hm(self): 34 | return HealthMonitor(self.client) 35 | 36 | @property 37 | def server(self): 38 | return Server(self.client) 39 | 40 | @property 41 | def service_group(self): 42 | return ServiceGroup(self.client) 43 | 44 | @property 45 | def template(self): 46 | return Template(self.client) 47 | 48 | @property 49 | def virtual_server(self): 50 | return VirtualServer(self.client) 51 | 52 | @property 53 | def aflex_policy(self): 54 | return AFlexPolicy(self.client) 55 | 56 | @property 57 | def tcp_proxy(self): 58 | return TcpProxy(self.client) 59 | 60 | @property 61 | def common(self): 62 | return SLBCommon(self.client) 63 | 64 | def all(self): 65 | return self._get('/slb/') 66 | -------------------------------------------------------------------------------- /acos_client/tests/unit/test_client.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from __future__ import absolute_import, unicode_literals 16 | 17 | from acos_client import client 18 | 19 | try: 20 | import unittest2 as unittest 21 | except ImportError: 22 | import unittest 23 | 24 | 25 | class TestClient(unittest.TestCase): 26 | 27 | def setUp(self): 28 | self.client_21 = client.Client('fake-host', '2.1', 'fake-username', 'fake-password', max_retries=5, timeout=3) 29 | self.client_30 = client.Client('fake-host', '3.0', 'fake-username', 'fake-password', max_retries=6, timeout=4) 30 | 31 | def test_dns_v21(self): 32 | from acos_client.v21.dns import DNS 33 | 34 | self.assertIsInstance(self.client_21.dns, DNS) 35 | 36 | def test_dns_v30(self): 37 | from acos_client.v30.dns import DNS 38 | 39 | self.assertIsInstance(self.client_30.dns, DNS) 40 | 41 | def test_max_retries_v21(self): 42 | 43 | self.assertEqual(self.client_21.max_retries, 5) 44 | self.assertEqual(self.client_21.timeout, 3) 45 | self.assertEqual(self.client_21.http.max_retries, 5) 46 | self.assertEqual(self.client_21.http.timeout, 3) 47 | 48 | def test_max_retries_v30(self): 49 | 50 | self.assertEqual(self.client_30.max_retries, 6) 51 | self.assertEqual(self.client_30.timeout, 4) 52 | self.assertEqual(self.client_30.http.max_retries, 6) 53 | self.assertEqual(self.client_30.http.timeout, 4) 54 | -------------------------------------------------------------------------------- /acos_client/v30/dns.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | 19 | 20 | class DNS(base.BaseV30): 21 | url_prefix = "/ip/dns/" 22 | 23 | def _set_dns(self, precedence, addr): 24 | addr_spec = {} 25 | 26 | if ':' in addr: 27 | addr_spec['ip-v6-addr'] = addr 28 | else: 29 | addr_spec['ip-v4-addr'] = addr 30 | 31 | payload = {precedence: addr_spec} 32 | 33 | return self._post(self.url_prefix + precedence, payload) 34 | 35 | def _set_suffix(self, suffix): 36 | 37 | payload = {'suffix': {'domain-name': suffix}} 38 | 39 | return self._post(self.url_prefix + 'suffix', payload) 40 | 41 | def set(self, primary=None, secondary=None, suffix=None): 42 | if primary is not None: 43 | self._set_dns('primary', primary) 44 | 45 | if secondary is not None: 46 | self._set_dns('secondary', secondary) 47 | 48 | if suffix is not None: 49 | self._set_suffix(suffix) 50 | 51 | def delete(self, primary=None, secondary=None, suffix=None): 52 | if suffix is not None: 53 | self._delete(self.url_prefix + 'suffix') 54 | 55 | if secondary is not None: 56 | self._delete(self.url_prefix + 'secondary') 57 | 58 | if primary is not None: 59 | self._delete(self.url_prefix + 'primary') 60 | -------------------------------------------------------------------------------- /acos_client/v21/slb/template/template_ssl.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | 19 | 20 | class BaseSSL(base.BaseV21): 21 | 22 | def get(self, name, **kwargs): 23 | return self._post(("slb.template.%s.search" % self.template_type), 24 | {'name': name}, **kwargs) 25 | 26 | def _set(self, action, name, cert_name, key_name, **kwargs): 27 | params = { 28 | "%s_template" % self.template_type: { 29 | "cert_name": cert_name, 30 | "key_name": key_name, 31 | "name": name 32 | } 33 | } 34 | self._post(action, params, **kwargs) 35 | 36 | def create(self, name, cert_name, key_name, **kwargs): 37 | self._set(("slb.template.%s.create" % self.template_type), 38 | name, cert_name, key_name, **kwargs) 39 | 40 | def update(self, name, cert_name, key_name, **kwargs): 41 | self._set(("slb.template.%s.update" % self.template_type), 42 | name, cert_name, key_name, **kwargs) 43 | 44 | def delete(self, name, **kwargs): 45 | self._post(("slb.template.%s.delete" % self.template_type), 46 | {"name": name}, **kwargs) 47 | 48 | 49 | class ClientSSL(BaseSSL): 50 | 51 | template_type = "client_ssl" 52 | 53 | 54 | class ServerSSL(BaseSSL): 55 | 56 | template_type = "server_ssl" 57 | -------------------------------------------------------------------------------- /acos_client/v30/slb/tcp_proxy.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019, Omkar Telee, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import six 18 | 19 | from acos_client import errors as acos_errors 20 | from acos_client.v30 import base 21 | 22 | 23 | class TcpProxy(base.BaseV30): 24 | 25 | # Proxy Protocol Version 26 | PROXY = "v1" 27 | PROXYV2 = "v2" 28 | 29 | url_prefix = '/slb/template/tcp-proxy/' 30 | 31 | def get(self, name, **kwargs): 32 | return self._get(self.url_prefix + name, **kwargs) 33 | 34 | def exists(self, name, **kwargs): 35 | try: 36 | self.get(name, **kwargs) 37 | return True 38 | except acos_errors.NotFound: 39 | return False 40 | 41 | def _set(self, name, version, **kwargs): 42 | 43 | params = { 44 | "tcp-proxy":{ 45 | "name": name, 46 | "proxy-header": { 47 | "proxy-header-action": "insert", 48 | "version": version 49 | } 50 | } 51 | } 52 | 53 | response = self._post(self.url_prefix, params, **kwargs) 54 | return response 55 | 56 | def create(self, name, version, **kwargs): 57 | return self._set(name, version, **kwargs) 58 | 59 | def update(self, name, version, **kwargs): 60 | return self._set(name, version, **kwargs) 61 | 62 | def delete(self, name): 63 | return self._delete(self.url_prefix + name) 64 | -------------------------------------------------------------------------------- /acos_client/v21/nat.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | from acos_client.v21 import base 16 | 17 | 18 | class Nat(base.BaseV21): 19 | @property 20 | def pool(self): 21 | return self.Pool(self.client) 22 | 23 | class Pool(base.BaseV21): 24 | def _set(self, action, name, start_ip, end_ip, mask, **kwargs): 25 | params = { 26 | 'name': name, 27 | 'start_ip_addr': start_ip, 28 | 'end_ip_addr': end_ip, 29 | 'netmask': mask, 30 | } 31 | return self._post(action, params, **kwargs) 32 | 33 | def all(self): 34 | return self._get('nat.pool.getAll') 35 | 36 | def create(self, name, start_ip, end_ip, mask, **kwargs): 37 | return self._set('nat.pool.create', name, start_ip, end_ip, mask, 38 | **kwargs) 39 | 40 | def update(self, name, start_ip, end_ip, mask, **kwargs): 41 | return self._set('nat.pool.create', name, start_ip, end_ip, mask, 42 | **kwargs) 43 | 44 | def delete(self, name, **kwargs): 45 | return self._post('nat.pool.delete', {"name": name}, **kwargs) 46 | 47 | def stats(self, name, **kwargs): 48 | return self._post('nat.pool.fetchStatistics', {"name": name}, 49 | **kwargs) 50 | 51 | def all_stats(self, **kwargs): 52 | return self._get('nat.pool.fetchALLStatistics', **kwargs) 53 | -------------------------------------------------------------------------------- /acos_client/v21/admin.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | from acos_client.v21 import base 16 | 17 | 18 | class Admin(base.BaseV21): 19 | 20 | @property 21 | def administrator(self): 22 | return self.Administrator(self.client) 23 | 24 | class Administrator(base.BaseV21): 25 | 26 | def all(self, **kwargs): 27 | return self._get('system.admin.administrator.getAll', **kwargs) 28 | 29 | def get(self, name, **kwargs): 30 | params = {"admin_name": name} 31 | return self._post('system.admin.administrator.search', params, **kwargs) 32 | 33 | def create(self, name, **kwargs): 34 | params = { 35 | "administrator": { 36 | "admin_name": name 37 | } 38 | } 39 | 40 | return self._post('system.admin.administrator.create', params, **kwargs) 41 | 42 | def update(self, name, **kwargs): 43 | params = { 44 | "administrator": { 45 | "admin_name": name 46 | } 47 | } 48 | 49 | return self._post('system.admin.administrator.update', params, **kwargs) 50 | 51 | def delete(self, name, **kwargs): 52 | params = {"admin_name": name} 53 | return self._post('system.admin.administrator.delete', params, **kwargs) 54 | 55 | def all_delete(self, **kwargs): 56 | return self._post('system.admin.administrator.deleteAll', **kwargs) 57 | -------------------------------------------------------------------------------- /acos_client/v30/session.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | 16 | class Session(object): 17 | 18 | def __init__(self, client, username, password): 19 | self.client = client 20 | self.http = client.http 21 | self.username = username 22 | self.password = password 23 | self.session_id = None 24 | 25 | @property 26 | def id(self): 27 | if self.session_id is None: 28 | self.authenticate(self.username, self.password) 29 | return self.session_id 30 | 31 | def authenticate(self, username, password): 32 | url = "/axapi/v3/auth" 33 | payload = { 34 | 'credentials': { 35 | "username": username, 36 | "password": password 37 | } 38 | } 39 | 40 | if self.session_id is not None: 41 | self.close() 42 | 43 | r = self.http.post(url, payload) 44 | if "authresponse" in r: 45 | self.session_id = str(r['authresponse']['signature']) 46 | else: 47 | self.session_id = None 48 | 49 | return r 50 | 51 | def close(self): 52 | try: 53 | self.client.partition.active() 54 | except Exception: 55 | pass 56 | 57 | if self.session_id is None: 58 | return 59 | 60 | try: 61 | h = {'Authorization': "A10 %s" % self.session_id} 62 | r = self.http.post('/axapi/v3/logoff', headers=h) 63 | finally: 64 | self.session_id = None 65 | 66 | return r 67 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v30/test_responses.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import unittest 18 | import uuid 19 | 20 | from acos_client import errors as ae 21 | from acos_client.v30 import responses as target 22 | 23 | 24 | class TestResponse(unittest.TestCase): 25 | def _build_test_response(self, code, msg): 26 | return { 27 | "response": { 28 | "err": { 29 | "code": code, 30 | "msg": msg 31 | } 32 | } 33 | } 34 | 35 | def _test_raise_axapi_ex(self, response, method, api_url): 36 | self.assertRaises(ae.NotFound, target.raise_axapi_ex, response, method, api_url) 37 | 38 | def test_raise_axapi_ex_NotFound(self): 39 | not_found_codes = [1023443968, 1023475727, 1207959957, 520749062, 1023410176, 1023410181] 40 | # 1023410181 is a special case. It matches on anything that's NOT DELETE and starts with 41 | # /axapi/v3/slb/service-group/.*/member/ 42 | # That probably needs to be fixed and this test should break when it does 43 | test_obj = uuid.uuid4() 44 | test_url = "/axapi/v3/object/{0}".format(test_obj) 45 | test_method = "GET" 46 | test_msg = "Could not find object {0}".format(test_obj) 47 | 48 | for x in not_found_codes: 49 | test_response = self._build_test_response(x, test_msg) 50 | self._test_raise_axapi_ex(test_response, test_method, test_url) 51 | -------------------------------------------------------------------------------- /acos_client/v30/overlay/options.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | 19 | 20 | class OverlayOptions(base.BaseV30): 21 | url_prefix = "/overlay-tunnel/options" 22 | 23 | def get(self, *args, **kwargs): 24 | return self._get(self.url_prefix, **kwargs) 25 | 26 | def update(self, gateway_mac, ip_dscp_preserve, 27 | nvgre_disable_flow_id, 28 | nvgre_key_mode_lower24, 29 | tcp_mss_adjust_disable, 30 | uuid, 31 | vxlan_dest_port, 32 | **kwargs): 33 | 34 | options = {} 35 | 36 | if gateway_mac: 37 | options["gateway-mac"] = gateway_mac 38 | 39 | if ip_dscp_preserve: 40 | options["ip-dscp-preserve"] = ip_dscp_preserve 41 | 42 | if nvgre_disable_flow_id: 43 | options["nvgre-disable-flow-id"] = nvgre_disable_flow_id 44 | 45 | if nvgre_key_mode_lower24: 46 | options["nvgre-key-mode-lower24"] = nvgre_key_mode_lower24 47 | 48 | if tcp_mss_adjust_disable: 49 | options["tcp-mss-adjust-disable"] = tcp_mss_adjust_disable 50 | 51 | if uuid: 52 | options["uuid"] = uuid 53 | 54 | if vxlan_dest_port: 55 | options["vxlan-dest-port"] = vxlan_dest_port 56 | 57 | payload = { 58 | "options": options 59 | } 60 | 61 | return self._post(self.url_prefix + "/options", payload, **kwargs) 62 | -------------------------------------------------------------------------------- /acos_client/v21/vrrp_a/vrrp_global.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | 19 | 20 | class VRRPAGlobal(base.BaseV21): 21 | def get(self, **kwargs): 22 | return self._get("vrrp_a.get", **kwargs) 23 | 24 | def set(self, status, device_id, set_id, default_vrid, hello_interval, dead_timer, 25 | track_event_delay, preemption_delay, arp_retry, 26 | vrid_list={}, 27 | preferred_session_sync_port_list={}): 28 | params = { 29 | "vrrp_a": { 30 | "status": status, 31 | "device_id": device_id, 32 | "set_id": set_id, 33 | "default_vrid": default_vrid, 34 | "hello_interval": hello_interval, 35 | "dead_timer": dead_timer, 36 | "track_event_delay": track_event_delay, 37 | "preemption_delay": preemption_delay, 38 | "arp_retry": arp_retry, 39 | } 40 | } 41 | vrids = self._convert_vrid_list(vrid_list) 42 | sync_ports = self._convert_sync_port_list(preferred_session_sync_port_list) 43 | 44 | if vrids: 45 | params["vrrp_a"]["vrid_list"] = vrids 46 | 47 | if sync_ports: 48 | params["vrrp_a"]["preferred_session_sync_port_list"] = sync_ports 49 | 50 | return self._post("vrrp_a.set", params) 51 | 52 | def _convert_vrid_list(self, vrids): 53 | return vrids 54 | 55 | def _convert_sync_port_list(self, sync_ports): 56 | return sync_ports 57 | -------------------------------------------------------------------------------- /acos_client/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | 18 | def acos_version_str2int(ver): 19 | if ver.isdigit(): 20 | return int(ver) 21 | else: 22 | vnum = "" 23 | for index in range(len(ver)): 24 | if ver[index].isdigit(): 25 | vnum = vnum + ver[index] 26 | else: 27 | break 28 | return int(vnum) 29 | 30 | 31 | def acos_revision_parse(revision): 32 | rev = [] 33 | revision_list = ['GR', 'P', 'SP'] 34 | for tag in revision_list: 35 | tag_index = revision.find(tag) 36 | if tag_index >= 0: 37 | tag_len = len(tag) 38 | rev.append(acos_version_str2int(revision[(tag_index + tag_len):])) 39 | else: 40 | rev.append(0) 41 | 42 | return tuple(rev) 43 | 44 | 45 | def acos_version(acos_version): 46 | major = acos_version_str2int(acos_version.split('.')[0]) 47 | minor = acos_version_str2int(acos_version.split('.')[1]) 48 | patch = acos_version_str2int(acos_version.split('.')[2]) 49 | 50 | revision = "" 51 | prev = acos_version.find('-') 52 | if prev > 0: 53 | revision = acos_version[prev + 1:].upper() 54 | gr, p, sp = acos_revision_parse(revision) 55 | 56 | return (major, minor, patch, gr, p, sp) 57 | 58 | 59 | def acos_version_cmp(ver1, ver2): 60 | vtup1 = acos_version(ver1) 61 | vtup2 = acos_version(ver2) 62 | for index in range(len(vtup1)): 63 | if vtup1[index] != vtup2[index]: 64 | return vtup1[index] - vtup2[index] 65 | return 0 66 | -------------------------------------------------------------------------------- /acos_client/v21/session.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import unicode_literals 17 | 18 | from acos_client import errors as acos_errors 19 | 20 | 21 | class Session(object): 22 | 23 | def __init__(self, client, username, password): 24 | self.client = client 25 | self.http = client.http 26 | self.username = username 27 | self.password = password 28 | self.session_id = None 29 | 30 | @property 31 | def id(self): 32 | if self.session_id is None: 33 | self.authenticate(self.username, self.password) 34 | return self.session_id 35 | 36 | def authenticate(self, username, password): 37 | url = "/services/rest/v2.1/?format=json&method=authenticate" 38 | params = { 39 | "username": username, 40 | "password": password 41 | } 42 | 43 | if self.session_id is not None: 44 | self.close() 45 | 46 | r = self.http.post(url, params) 47 | self.session_id = r['session_id'] 48 | return r 49 | 50 | def close(self): 51 | try: 52 | self.client.partition.active() 53 | except Exception: 54 | pass 55 | 56 | try: 57 | url = ("/services/rest/v2.1/?format=json&method=session" 58 | ".close&session_id=%s" % self.session_id) 59 | 60 | r = self.http.post(url, {"session_id": self.session_id}) 61 | except acos_errors.InvalidPartitionParameter: 62 | pass 63 | finally: 64 | self.session_id = None 65 | 66 | return r 67 | -------------------------------------------------------------------------------- /acos_client/v21/ssl_adapter.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import logging 16 | from requests.adapters import HTTPAdapter 17 | import ssl 18 | 19 | FORCED_CIPHERS = ( 20 | 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' 21 | 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES' 22 | ) 23 | 24 | 25 | class SSLAdapter(HTTPAdapter): 26 | """A TransportAdapter that re-enables 3DES support in Requests. 27 | 28 | """ 29 | 30 | def create_ssl_context(self): 31 | ctx = ssl.create_default_context() 32 | # Disable all encryption protcols except TLS1_0 33 | ctx.options |= ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 34 | # Try-Except here because OP_NO_TLSv1_3 not available in Python3 before 3.6 35 | try: 36 | ctx.options |= ssl.OP_NO_TLSv1_3 | ssl.OP_NO_TLSv1_2 | ssl.OP_NO_TLSv1_1 37 | except(AttributeError): 38 | ctx.options |= ssl.OP_NO_TLSv1_2 | ssl.OP_NO_TLSv1_1 39 | ctx.set_ciphers(FORCED_CIPHERS) 40 | ctx.check_hostname = False 41 | return ctx 42 | 43 | def init_poolmanager(self, *args, **kwargs): 44 | logging.debug(' ----------- SSLAdapter.init_poolmanager -------------- ') 45 | kwargs['ssl_context'] = self.create_ssl_context() 46 | return super(SSLAdapter, self).init_poolmanager(*args, **kwargs) 47 | 48 | def proxy_manager_for(self, *args, **kwargs): 49 | logging.debug(' ----------- SSLAdapter.proxy_manager_for -------------- ') 50 | kwargs['ssl_context'] = self.create_ssl_context() 51 | return super(SSLAdapter, self).proxy_manager_for(*args, **kwargs) 52 | -------------------------------------------------------------------------------- /acos_client/v30/file/ssl_key.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015, Tobit Raff, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | import six 17 | 18 | 19 | from acos_client import errors as acos_errors 20 | from acos_client.v30 import base 21 | 22 | 23 | class SSLKey(base.BaseV30): 24 | 25 | url_prefix = '/file/ssl-key/' 26 | 27 | def get(self, file): 28 | return self._get(self.url_prefix + file) 29 | 30 | def exists(self, file): 31 | try: 32 | self.get(file) 33 | return True 34 | except acos_errors.NotFound: 35 | return False 36 | 37 | def _set(self, file="", cert="", size="", action="", **kwargs): 38 | 39 | obj_params = { 40 | "file": file, 41 | "file-handle": file, 42 | "action": action, 43 | } 44 | 45 | kwargs['params'] = {'ssl-key': {}} 46 | 47 | for key, val in six.iteritems(obj_params): 48 | # Filter out invalid, or unset keys 49 | if val != "": 50 | kwargs['params']['ssl-key'][key] = val 51 | 52 | return self._post(self.url_prefix, file_name=obj_params["file"], 53 | file_content=cert, **kwargs) 54 | 55 | def create(self, file="", cert="", size="", action=""): 56 | if self.exists(file): 57 | raise acos_errors.Exists 58 | 59 | self._set(file, cert, size, action) 60 | 61 | def update(self, file="", cert="", size="", action=""): 62 | self._set(file, cert, size, action) 63 | 64 | def delete(self, private_key=""): 65 | payload = {"delete": {"private-key": private_key}} 66 | self._request("POST", "/pki/delete", payload) 67 | -------------------------------------------------------------------------------- /acos_client/v21/slb/virtual_service.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | from acos_client.v21 import base 16 | 17 | 18 | class VirtualService(base.BaseV21): 19 | 20 | def all(self, **kwargs): 21 | return self._get("slb.virtual_service.getAll", **kwargs) 22 | 23 | def get(self, name, **kwargs): 24 | return self._post("slb.virtual_service.search", {'name': name}, 25 | **kwargs) 26 | 27 | def _set(self, action, name, protocol, port, **kwargs): 28 | params = { 29 | "virtual_service": { 30 | "port": port, 31 | "protocol": protocol, 32 | "name": name 33 | } 34 | } 35 | 36 | return self._post(action, params, **kwargs) 37 | 38 | def create(self, name, protocol, port, **kwargs): 39 | return self._set("slb.virtual_service.create", name, protocol, port, 40 | **kwargs) 41 | 42 | def update(self, name, protocol, port, **kwargs): 43 | return self._set("slb.virtual_service.update", name, protocol, port, 44 | **kwargs) 45 | 46 | def delete(self, name, **kwargs): 47 | return self._post("slb.virtual_service.delete", {"name": name}, 48 | **kwargs) 49 | 50 | def all_delete(self, **kwargs): 51 | return self._get("slb.virtual_service.deleteAll", **kwargs) 52 | 53 | def stats(self, name, **kwargs): 54 | return self._post("slb.virtual_service.fetchStatistics", 55 | {"name": name}, **kwargs) 56 | 57 | def all_stats(self, **kwargs): 58 | return self._get("slb.virtual_service.fetchAllStatistics", **kwargs) 59 | -------------------------------------------------------------------------------- /acos_client/v21/slb/class_list.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | import json 16 | import re 17 | 18 | from acos_client import multipart 19 | from acos_client.v21 import base 20 | 21 | 22 | class ClassList(base.BaseV21): 23 | 24 | @staticmethod 25 | def _fix_json(data): 26 | p = re.compile(r'(?<=[^:{\[,])"(?![:,}\]])') 27 | return json.loads(re.sub(p, '\\"', data)) 28 | 29 | def all(self, **kwargs): 30 | return self._fix_json(self._get("slb.class_list.getAll", **kwargs)) 31 | 32 | def get(self, name, **kwargs): 33 | return ClassList._fix_json(self._post("slb.class_list.search", 34 | {'name': name}, **kwargs)) 35 | 36 | def download(self, name, **kwargs): 37 | return self._post('slb.class_list.download', 38 | params={'file_name': name}, **kwargs) 39 | 40 | def upload(self, name, class_list, **kwargs): 41 | m = multipart.Multipart() 42 | m.file(name=name, filename=name, value=class_list) 43 | ct, payload = m.get() 44 | kwargs.update(payload=payload, headers={'Content-type': ct}) 45 | return self._post('slb.class_list.upload', **kwargs) 46 | 47 | def _set(self, action, class_list, **kwargs): 48 | return self._post(action, class_list, **kwargs) 49 | 50 | def create(self, class_list, **kwargs): 51 | return self._set("slb.class_list.create", class_list, **kwargs) 52 | 53 | def update(self, class_list, **kwargs): 54 | return self._set("slb.class_list.update", class_list, **kwargs) 55 | 56 | def delete(self, name, **kwargs): 57 | self._post("slb.class_list.delete", {"name": name}, **kwargs) 58 | -------------------------------------------------------------------------------- /acos_client/v21/slb/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import acos_client.v21.base as base 16 | 17 | from acos_client.v21.slb.aflex import Aflex 18 | from acos_client.v21.slb.class_list import ClassList 19 | from acos_client.v21.slb.hm import HealthMonitor 20 | from acos_client.v21.slb.server import Server 21 | from acos_client.v21.slb.service_group import ServiceGroup 22 | from acos_client.v21.slb.template import Template 23 | from acos_client.v21.slb.virtual_server import VirtualServer 24 | from acos_client.v21.slb.virtual_service import VirtualService 25 | 26 | 27 | class SLB(base.BaseV21): 28 | # For status args 29 | DOWN = 0 30 | UP = 1 31 | 32 | @property 33 | def hm(self): 34 | return HealthMonitor(self.client) 35 | 36 | @property 37 | def server(self): 38 | return Server(self.client) 39 | 40 | @property 41 | def service_group(self): 42 | return ServiceGroup(self.client) 43 | 44 | @property 45 | def template(self): 46 | return Template(self.client) 47 | 48 | @property 49 | def virtual_server(self): 50 | return VirtualServer(self.client) 51 | 52 | @property 53 | def aflex(self): 54 | return Aflex(self.client) 55 | 56 | @property 57 | def class_list(self): 58 | return ClassList(self.client) 59 | 60 | @property 61 | def virtual_service(self): 62 | return VirtualService(self.client) 63 | 64 | @property 65 | def common(self): 66 | raise NotImplementedError("slb.common support is not available using AXAPI v2.1") 67 | 68 | 69 | class File(base.BaseV21): 70 | @property 71 | def ssl_key(self): 72 | raise NotImplementedError("Not implemented in AXAPI v2.1") 73 | 74 | @property 75 | def ssl_cert(self): 76 | raise NotImplementedError("Not implemented in AXAPI v2.1") 77 | -------------------------------------------------------------------------------- /acos_client/v21/slb/member.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | 19 | 20 | class Member(base.BaseV21): 21 | 22 | def _write(self, action, service_group_name, server_name, server_port, 23 | status=None, **kwargs): 24 | params = { 25 | "name": service_group_name, 26 | "member": self.minimal_dict({ 27 | "server": server_name, 28 | "port": int(server_port), 29 | "status": status 30 | }) 31 | } 32 | self._post(action, params, **kwargs) 33 | 34 | def create(self, service_group_name, server_name, server_port, status=1, 35 | **kwargs): 36 | self._write("slb.service_group.member.create", service_group_name, 37 | server_name, server_port, status, **kwargs) 38 | 39 | def update(self, service_group_name, server_name, server_port, status=1, 40 | **kwargs): 41 | self._write("slb.service_group.member.update", service_group_name, 42 | server_name, server_port, status, **kwargs) 43 | 44 | def delete(self, service_group_name, server_name, server_port, **kwargs): 45 | self._write("slb.service_group.member.delete", service_group_name, 46 | server_name, int(server_port), **kwargs) 47 | 48 | def get_oper(self, service_group_name, server_name, server_port, **kwargs): 49 | sg_stats = self._post("slb.service_group.fetchStatistics", 50 | {"name": service_group_name}, **kwargs) 51 | members_stats = sg_stats["service_group_stat"]["member_stat_list"] 52 | member_stats = filter(lambda x: x.get("server") == server_name, members_stats) 53 | return member_stats 54 | -------------------------------------------------------------------------------- /acos_client/v21/slb/template/persistence.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client import errors as acos_errors 18 | from acos_client.v21 import base 19 | 20 | 21 | class BasePersistence(base.BaseV21): 22 | 23 | def __init__(self, client): 24 | super(BasePersistence, self).__init__(client) 25 | self.prefix = "slb.template.%s_persistence" % self.pers_type 26 | 27 | def get(self, name, **kwargs): 28 | return self._post(("%s.search" % self.prefix), {'name': name}, 29 | **kwargs) 30 | 31 | def exists(self, name, **kwargs): 32 | try: 33 | self.get(name, **kwargs) 34 | return True 35 | except acos_errors.NotFound: 36 | return False 37 | 38 | def create(self, name, **kwargs): 39 | self._post(("%s.create" % self.prefix), self.get_params(name), 40 | **kwargs) 41 | 42 | def delete(self, name, **kwargs): 43 | self._post(("%s.delete" % self.prefix), {'name': name}, **kwargs) 44 | 45 | 46 | class CookiePersistence(BasePersistence): 47 | 48 | def __init__(self, client): 49 | self.pers_type = 'cookie' 50 | super(CookiePersistence, self).__init__(client) 51 | 52 | def get_params(self, name): 53 | return { 54 | "cookie_persistence_template": { 55 | "name": name 56 | } 57 | } 58 | 59 | 60 | class SourceIpPersistence(BasePersistence): 61 | 62 | def __init__(self, client): 63 | self.pers_type = 'src_ip' 64 | super(SourceIpPersistence, self).__init__(client) 65 | 66 | def get_params(self, name): 67 | return { 68 | "src_ip_persistence_template": { 69 | "name": name 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /acos_client/v21/action.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import six 18 | import time 19 | 20 | from acos_client import errors as acos_errors 21 | from acos_client.v21 import base 22 | 23 | 24 | class Action(base.BaseV21): 25 | 26 | def write_memory(self): 27 | try: 28 | self._get("system.action.write_memory") 29 | except acos_errors.InvalidPartitionParameter: 30 | pass 31 | 32 | def reboot(self, **kwargs): 33 | raise NotImplementedError 34 | # return self._post("system.action.reboot", **kwargs) 35 | 36 | def reload(self, write_memory=False, **kwargs): 37 | # write_memory param is required but no matter what value is passed 38 | # it will ALWAYS save pending changes 39 | write_memory = 1 if write_memory else 0 40 | return self._post("system.action.reload", 41 | params={"write_memory": write_memory}, **kwargs) 42 | 43 | def activate_and_write(self, partition, **kwargs): 44 | write_cmd = "write memory\r\n" 45 | 46 | if partition is not None: 47 | write_cmd = "active-partition {0}\r\n{1}".format(partition, write_cmd) 48 | 49 | last_e = None 50 | for i in six.moves.range(0, 5): 51 | # Request raises an exception when the "maybe error" is returned. 52 | try: 53 | return self._request("POST", "cli.deploy", params=None, payload=write_cmd, **kwargs) 54 | except acos_errors.ACOSException as e: 55 | last_e = e 56 | # Catch 'might fail error' 57 | if e.msg.startswith("write memory") or '2039 ' in e.msg: 58 | time.sleep(1) 59 | continue 60 | raise e 61 | 62 | if last_e is not None: 63 | raise last_e 64 | -------------------------------------------------------------------------------- /acos_client/v21/base.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import time 18 | 19 | from acos_client import errors as acos_errors 20 | 21 | 22 | class BaseV21(object): 23 | 24 | def __init__(self, client): 25 | self.client = client 26 | 27 | def minimal_dict(self, my_dict): 28 | return dict((k, v) for k, v in my_dict.items() if v is not None) 29 | 30 | def url(self, action): 31 | return ("/services/rest/v2.1/?format=json&method=%s&session_id=%s" % 32 | (action, self.client.session.id)) 33 | 34 | def _request(self, method, action, params, retry_count=0, **kwargs): 35 | if retry_count > 6: 36 | raise acos_errors.ACOSUnknownError() 37 | 38 | try: 39 | return self.client.http.request(method, self.url(action), params, 40 | **kwargs) 41 | except acos_errors.MemoryFault as e: 42 | if retry_count < 5: 43 | time.sleep(0.1) 44 | return self._request(method, action, params, retry_count + 1, **kwargs) 45 | raise e 46 | except acos_errors.InvalidSessionID as e: 47 | if retry_count < 5: 48 | time.sleep(0.1) 49 | try: 50 | p = self.client.current_partition 51 | self.client.session.close() 52 | self.client.partition.active(p) 53 | except Exception: 54 | pass 55 | return self._request(method, action, params, retry_count + 1, **kwargs) 56 | raise e 57 | 58 | def _get(self, action, params={}, **kwargs): 59 | return self._request('GET', action, params, **kwargs) 60 | 61 | def _post(self, action, params={}, **kwargs): 62 | return self._request('POST', action, params, **kwargs) 63 | -------------------------------------------------------------------------------- /acos_client/v30/slb/template/persistence.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client import errors as acos_errors 18 | from acos_client.v30 import base 19 | 20 | 21 | class BasePersistence(base.BaseV30): 22 | 23 | def __init__(self, client): 24 | super(BasePersistence, self).__init__(client) 25 | self.prefix = "/slb/template/persist/%s/" % self.pers_type 26 | 27 | def get(self, name, **kwargs): 28 | return self._get(self.prefix + name, **kwargs) 29 | 30 | def exists(self, name): 31 | try: 32 | self.get(name) 33 | return True 34 | except acos_errors.NotFound: 35 | return False 36 | 37 | def create(self, name, **kwargs): 38 | if self.exists(name): 39 | raise acos_errors.Exists 40 | self._post(self.prefix, 41 | self.get_params(name, 42 | cookie_name=kwargs.get("cookie_name")), 43 | **kwargs) 44 | 45 | def delete(self, name, **kwargs): 46 | self._delete(self.prefix + name, **kwargs) 47 | 48 | 49 | class CookiePersistence(BasePersistence): 50 | 51 | def __init__(self, client): 52 | self.pers_type = 'cookie' 53 | super(CookiePersistence, self).__init__(client) 54 | 55 | def get_params(self, name, **kwargs): 56 | return { 57 | "cookie": { 58 | "name": name, 59 | "cookie-name": kwargs.get("cookie_name") 60 | } 61 | } 62 | 63 | 64 | class SourceIpPersistence(BasePersistence): 65 | 66 | def __init__(self, client): 67 | self.pers_type = 'source-ip' 68 | super(SourceIpPersistence, self).__init__(client) 69 | 70 | def get_params(self, name, **kwargs): 71 | return { 72 | "source-ip": { 73 | "name": name 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /acos_client/v30/file/ssl_cert.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015, Tobit Raff, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import six 18 | 19 | from acos_client import errors as acos_errors 20 | from acos_client.v30 import base 21 | 22 | 23 | class SSLCert(base.BaseV30): 24 | 25 | url_prefix = '/file/ssl-cert/' 26 | 27 | def get(self, file, **kwargs): 28 | return self._get(self.url_prefix + file, **kwargs) 29 | 30 | def exists(self, file): 31 | try: 32 | self.get(file) 33 | return True 34 | except acos_errors.NotFound: 35 | return False 36 | 37 | def _set(self, file="", cert="", size="", certificate_type="", action="", **kwargs): 38 | 39 | obj_params = { 40 | "file": file, 41 | "file-handle": file, 42 | "certificate-type": certificate_type, 43 | "action": action, 44 | } 45 | 46 | kwargs['params'] = {'ssl-cert': {}} 47 | 48 | for key, val in six.iteritems(obj_params): 49 | # Filter out invalid, or unset keys 50 | if val != "": 51 | kwargs['params']['ssl-cert'][key] = val 52 | 53 | return self._post(self.url_prefix, file_name=obj_params["file"], 54 | file_content=cert, **kwargs) 55 | 56 | def create(self, file="", cert="", size="", certificate_type="", action="", **kwargs): 57 | if self.exists(file): 58 | raise acos_errors.Exists 59 | 60 | self._set(file, cert, size, certificate_type, action, **kwargs) 61 | 62 | def update(self, file="", cert="", size="", certificate_type="", action="", **kwargs): 63 | self._set(file, cert, size, certificate_type, action, update=True, **kwargs) 64 | 65 | def delete(self, private_key="", cert_name=""): 66 | payload = {"delete": {"private-key": private_key, "cert-name": cert_name}} 67 | self._request("POST", "/pki/delete", payload) 68 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v30/test_sflow.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | try: 18 | import unittest 19 | from unittest import mock 20 | except ImportError: 21 | import mock 22 | import unittest2 as unittest 23 | 24 | from acos_client.v30 import sflow 25 | 26 | 27 | class TestSFlow(unittest.TestCase): 28 | def setUp(self): 29 | self.client = mock.MagicMock() 30 | self.target = sflow.SFlow(self.client) 31 | 32 | def test_collector_ip_create(self): 33 | ip_address = "127.0.0.1" 34 | port = 4242 35 | self.target.collector.ip.create(ip_address, port) 36 | expected = {"ip": [{"addr": ip_address, "port": int(port)}]} 37 | actual = self.client.http.request.call_args[0] 38 | self.assertTrue(expected in actual) 39 | 40 | def test_collector_ip_get(self): 41 | ip_address = "127.0.0.1" 42 | port = 4242 43 | 44 | self.target.collector.ip.get(ip_address, port) 45 | expected = "/axapi/v3/sflow/collector/ip/{0}+{1}".format(ip_address, port) 46 | actual = self.client.http.request.call_args[0] 47 | self.assertTrue(expected in actual) 48 | 49 | def test_setting_create(self): 50 | self.target.setting.create(None, None, None, 1) 51 | expected = {'setting': { 52 | 'counter-polling-interval': 1}} 53 | actual = self.client.http.request.call_args[0] 54 | self.assertTrue(expected in actual) 55 | 56 | def _test_polling_create(self, http_counter=False): 57 | self.target.polling.create(http_counter) 58 | expected = {'polling': {'http-counter': int(http_counter)}} 59 | actual = self.client.http.request.call_args[0] 60 | self.assertTrue(expected in actual) 61 | 62 | def test_polling_create_http_counter_negative(self): 63 | self._test_polling_create() 64 | 65 | def test_polling_create_http_counter_positive(self): 66 | self._test_polling_create(True) 67 | -------------------------------------------------------------------------------- /acos_client/v30/slb/aflex_policy.py: -------------------------------------------------------------------------------- 1 | # Copyright 2019, Omkar Telee, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import six 18 | 19 | from acos_client import errors as acos_errors 20 | from acos_client.v30 import base 21 | 22 | 23 | class AFlexPolicy(base.BaseV30): 24 | 25 | url_prefix = '/file/aflex/' 26 | 27 | def get(self, file, **kwargs): 28 | return self._get(self.url_prefix + file, **kwargs) 29 | 30 | def exists(self, file): 31 | try: 32 | self.get(file) 33 | return True 34 | except acos_errors.NotFound: 35 | return False 36 | 37 | def _set(self, file="", script="", size="", action="", **kwargs): 38 | 39 | obj_params = { 40 | "file": file, 41 | "file-handle": file, 42 | "action": action, 43 | } 44 | kwargs['params'] = {'aflex': {}} 45 | 46 | for key, val in six.iteritems(obj_params): 47 | # Filter out invalid, or unset keys 48 | if val != "": 49 | kwargs['params']['aflex'][key] = val 50 | print(script) 51 | response = self._post(self.url_prefix, file_name=file, 52 | file_content=script, **kwargs) 53 | return response 54 | 55 | def create(self, file="", script="", size="", action="", **kwargs): 56 | return self._set(file, script, size, action, **kwargs) 57 | 58 | def update(self, file="", script="", size="", action="", **kwargs): 59 | return self._set(file, script, size, action, **kwargs) 60 | 61 | def delete(self, l7policyid, **kwargs): 62 | file = l7policyid 63 | obj_params = { 64 | "file": file, 65 | "action": "delete", 66 | } 67 | kwargs['params'] = {'aflex': {}} 68 | 69 | for key, val in six.iteritems(obj_params): 70 | # Filter out invalid, or unset keys 71 | if val != "": 72 | kwargs['params']['aflex'][key] = val 73 | 74 | return self._post(self.url_prefix, file_name=file, 75 | file_content="", **kwargs) 76 | -------------------------------------------------------------------------------- /acos_client/v21/slb/server.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | from acos_client.v21.slb.port import Port 19 | 20 | 21 | class Server(base.BaseV21): 22 | 23 | def get(self, name, **kwargs): 24 | return self._post("slb.server.search", {'name': name}, **kwargs) 25 | 26 | def create(self, name, ip_address, status=1, **kwargs): 27 | params = { 28 | "server": { 29 | "name": name, 30 | "host": ip_address, 31 | "status": status, 32 | "conn_resume": kwargs.get("conn_resume", 0), 33 | "conn_limit": kwargs.get("conn_limit", 8000000), 34 | } 35 | } 36 | self._post("slb.server.create", params, **kwargs) 37 | 38 | def update(self, name, ip_address, status=1, **kwargs): 39 | params = { 40 | "server": { 41 | "name": name, 42 | "host": ip_address, 43 | "status": status, 44 | "conn_resume": kwargs.get("conn_resume", 0), 45 | "conn_limit": kwargs.get("conn_limit", 8000000), 46 | } 47 | } 48 | self._post("slb.server.update", params, **kwargs) 49 | 50 | def fetchStatistics(self, name, **kwargs): 51 | return self._post("slb.server.fetchStatistics", {"name": name}, 52 | **kwargs) 53 | 54 | def delete(self, name, **kwargs): 55 | self._post("slb.server.delete", {"server": {"name": name}}, **kwargs) 56 | 57 | def all(self, **kwargs): 58 | return self._get('slb.server.getAll', **kwargs) 59 | 60 | def all_delete(self, **kwargs): 61 | self._get('slb.server.deleteAll', **kwargs) 62 | 63 | def stats(self, name, **kwargs): 64 | return self._post("slb.server.fetchStatistics", 65 | {"server": {"name": name}}, **kwargs) 66 | 67 | def all_stats(self, **kwargs): 68 | return self._get('fetchAllStatistics', **kwargs) 69 | 70 | @property 71 | def port(self): 72 | return Port(self.client) 73 | -------------------------------------------------------------------------------- /acos_client/v30/glm/proxy.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from acos_client.v30 import base 16 | 17 | 18 | class SecretStringUndefinedException(Exception): 19 | 20 | def __init__(self): 21 | self.message = ("The secret_string argument must " 22 | "be defined if password is specified.") 23 | super(SecretStringUndefinedException, self).__init__(self.message) 24 | 25 | 26 | class ProxyServer(base.BaseV30): 27 | url_prefix = '/glm/proxy-server' 28 | 29 | def _set(self, host=None, port=None, username=None, 30 | password=None, secret_string=None): 31 | params = { 32 | 'proxy-server': { 33 | 'host': host, 34 | 'port': port, 35 | 'username': username, 36 | 'password': password, 37 | 'secret-string': secret_string 38 | } 39 | } 40 | 41 | if password and not secret_string: 42 | raise SecretStringUndefinedException() 43 | 44 | return params 45 | 46 | def create(self, host=None, port=None, username=None, 47 | password=None, secret_string=None, **kwargs): 48 | params = self._set(host=host, port=port, username=username, 49 | password=password, secret_string=secret_string) 50 | return self._post(self.url_prefix, params, axapi_args=kwargs) 51 | 52 | def update(self, host=None, port=None, username=None, 53 | password=None, secret_string=None, **kwargs): 54 | params = self._set(host=host, port=port, username=username, 55 | password=password, secret_string=secret_string) 56 | return self._post(self.url_prefix, params, axapi_args=kwargs) 57 | 58 | def put(self, host=None, port=None, username=None, 59 | password=None, secret_string=None, **kwargs): 60 | params = self._set(host=host, port=port, username=username, 61 | password=password, secret_string=secret_string) 62 | return self._put(self.url_prefix, params, axapi_args=kwargs) 63 | 64 | def delete(self): 65 | return self._delete(self.url_prefix) 66 | -------------------------------------------------------------------------------- /acos_client/v21/slb/virtual_server.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | from acos_client.v21.slb.virtual_port import VirtualPort 19 | 20 | 21 | class VirtualServer(base.BaseV21): 22 | 23 | @property 24 | def vport(self): 25 | return VirtualPort(self.client) 26 | 27 | def all(self, **kwargs): 28 | return self._get("slb.virtual_server.getAll", **kwargs) 29 | 30 | def get(self, name, **kwargs): 31 | return self._post("slb.virtual_server.search", {'name': name}, 32 | **kwargs) 33 | 34 | def _set(self, action, name, ip_address=None, status=1, vrid=None, template_virtual_server=None, **kwargs): 35 | params = { 36 | "virtual_server": self.minimal_dict({ 37 | "name": name, 38 | "address": ip_address, 39 | "status": status, 40 | }), 41 | } 42 | if vrid: 43 | params['virtual_server']['vrid'] = int(vrid) 44 | if template_virtual_server: 45 | params['virtual_server']['vip_template'] = str(template_virtual_server) 46 | 47 | return self._post(action, params, **kwargs) 48 | 49 | def create(self, name, ip_address, status=1, vrid=None, template_virtual_server=None, **kwargs): 50 | return self._set( 51 | "slb.virtual_server.create", name, ip_address, status, vrid, template_virtual_server, **kwargs 52 | ) 53 | 54 | def update(self, name, ip_address=None, status=1, vrid=None, template_virtual_server=None, **kwargs): 55 | return self._set( 56 | "slb.virtual_server.update", name, ip_address, status, vrid, template_virtual_server, **kwargs) 57 | 58 | def delete(self, name, **kwargs): 59 | return self._post("slb.virtual_server.delete", {"name": name}, **kwargs) 60 | 61 | def stats(self, name, **kwargs): 62 | return self._post("slb.virtual_server.fetchStatistics", {"name": name}, 63 | **kwargs) 64 | 65 | def all_stats(self, **kwargs): 66 | return self._get("slb.virtual_server.fetchAllStatistics", **kwargs) 67 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v21/test_interfaces.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import unicode_literals 17 | 18 | try: 19 | import unittest2 as unittest 20 | except ImportError: 21 | import unittest 22 | 23 | from acos_client import client 24 | import responses 25 | 26 | 27 | HOSTNAME = 'fake_a10' 28 | BASE_URL = "https://{}:443/services/rest/v2.1/?format=json&method=".format(HOSTNAME) 29 | AUTH_URL = "{}authenticate".format(BASE_URL) 30 | INTERFACE_GET_URL = '{}network.interface.get&session_id={}'.format(BASE_URL, 'foobar') 31 | INTERFACE_GET_LIST_URL = '{}network.interface.getAll&session_id={}'.format(BASE_URL, 'foobar') 32 | 33 | 34 | class TestInterfaceGet(unittest.TestCase): 35 | 36 | def setUp(self): 37 | self.client = client.Client(HOSTNAME, '21', 'fake_username', 'fake_password') 38 | 39 | @responses.activate 40 | def test_interface_get(self): 41 | responses.add(responses.POST, AUTH_URL, json={'session_id': 'foobar'}) 42 | json_response = { 43 | "interface": {"port_num": 1, "type": "ethernet", } 44 | } 45 | responses.add(responses.POST, INTERFACE_GET_URL, json=json_response, status=200) 46 | 47 | resp = self.client.interface.ethernet.get(1) 48 | 49 | self.assertEqual(resp, json_response) 50 | self.assertEqual(len(responses.calls), 2) 51 | self.assertEqual(responses.calls[1].request.method, responses.POST) 52 | self.assertEqual(responses.calls[1].request.url, INTERFACE_GET_URL) 53 | 54 | @responses.activate 55 | def test_interface_get_list(self): 56 | responses.add(responses.POST, AUTH_URL, json={'session_id': 'foobar'}) 57 | json_response = [ 58 | {"interface": {"port_num": 1, "type": "ethernet", }}, {"interface": {"port_num": 2, "type": "ethernet", }} 59 | ] 60 | responses.add(responses.GET, INTERFACE_GET_LIST_URL, json=json_response, status=200) 61 | 62 | resp = self.client.interface.get_list() 63 | 64 | self.assertEqual(resp, json_response) 65 | self.assertEqual(len(responses.calls), 2) 66 | self.assertEqual(responses.calls[1].request.method, responses.GET) 67 | self.assertEqual(responses.calls[1].request.url, INTERFACE_GET_LIST_URL) 68 | -------------------------------------------------------------------------------- /acos_client/v21/slb/aflex.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | from acos_client import multipart 16 | from acos_client.v21 import base 17 | 18 | 19 | class Aflex(base.BaseV21): 20 | 21 | def _set(self, action, name, aflex, **kwargs): 22 | m = multipart.Multipart() 23 | m.file(name="upload_aflex", filename=name, value=aflex) 24 | ct, payload = m.get() 25 | kwargs.update(payload=payload, headers={'Content-type': ct}) 26 | return self._post(action, **kwargs) 27 | 28 | def upload(self, name, aflex, **kwargs): 29 | return self._set('slb.aflex.upload', name, aflex, **kwargs) 30 | 31 | def update(self, name, aflex, **kwargs): 32 | return self._set('slb.aflex.update', name, aflex, **kwargs) 33 | 34 | def all(self, **kwargs): 35 | return self._get('slb.aflex.getAll') 36 | 37 | def get(self, name, **kwargs): 38 | return self._post('slb.aflex.search', {'name': name}, 39 | **kwargs) 40 | 41 | def download(self, name, **kwargs): 42 | return self._post('slb.aflex.download', {'name': name}, 43 | **kwargs) 44 | 45 | def delete(self, name, **kwargs): 46 | self._post('slb.aflex.delete', {'name': name}, 47 | **kwargs) 48 | 49 | def stats(self, name, **kwargs): 50 | return self._post("slb.aflex.fetchStatistics", {"name": name}, 51 | **kwargs) 52 | 53 | def all_stats(self, **kwargs): 54 | return self._get("slb.aflex.fetchAllstatistics", **kwargs) 55 | 56 | def clear_stats(self, name, **kwargs): 57 | return self._post("slb.aflex.slb.aflex.clearStatistics", 58 | {"name": name}, **kwargs) 59 | 60 | def clear_all_stats(self, **kwargs): 61 | return self._post("slb.aflex.clearAllStatistics", **kwargs) 62 | 63 | def clear_events(self, name, event_name, **kwargs): 64 | params = { 65 | "aflex_event": { 66 | "name": name, 67 | "event_name": event_name 68 | } 69 | } 70 | return self._post("slb.aflex.clearEvents", params, **kwargs) 71 | 72 | def clear_all_events(self, **kwargs): 73 | return self._post("slb.aflax.clearAllEvents", **kwargs) 74 | -------------------------------------------------------------------------------- /acos_client/v30/route.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015, A10 Networks 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client import errors as acos_errors 18 | from acos_client.v30 import base 19 | 20 | 21 | class RIB(base.BaseV30): 22 | """Manipulation of Routing Information Base""" 23 | url_prefix = "/ip/route/rib" 24 | 25 | def create(self, destination, mask, next_hops=[]): 26 | """Create route to {destination} {mask} using {next_hops} expressed as (gateway, distance)""" 27 | payload = { 28 | "rib": self._build_payload(destination, mask, next_hops) 29 | } 30 | 31 | return self._post(self.url_prefix, payload) 32 | 33 | def get(self, destination, mask): 34 | return self._get(self._build_url(destination, mask)) 35 | 36 | def exists(self, destination, mask): 37 | try: 38 | self.get(destination, mask) 39 | return True 40 | except acos_errors.NotFound: 41 | return False 42 | 43 | def delete(self, destination, mask): 44 | return self._delete(self._build_url(destination, mask)) 45 | 46 | def update(self, destination, mask, next_hops=[]): 47 | payload = { 48 | "rib": self._build_payload(destination, mask, next_hops) 49 | } 50 | return self._put(self._build_url(destination, mask), payload) 51 | 52 | def get_all(self): 53 | return self._get(self.url_prefix) 54 | 55 | def _build_nexthops(self, nexthops): 56 | hops = [] 57 | for ip, dist in nexthops: 58 | hops.append({"ip-next-hop": ip, "distance-nexthop-ip": dist}) 59 | return hops 60 | 61 | def _build_payload(self, destination, mask, next_hops): 62 | hop_array = self._build_nexthops(next_hops) 63 | 64 | payload = { 65 | "ip-dest-addr": destination, 66 | "ip-mask": mask 67 | } 68 | 69 | if len(hop_array) > 0: 70 | payload["ip-nexthop-ipv4"] = hop_array 71 | 72 | return payload 73 | 74 | def _build_url(self, destination, mask): 75 | # Self explanatory except the mask. We're trimming the leading / for CIDRs expressed in bits 76 | # We'd use a URL encoder but it's an edge case. 77 | return "{urlbase}/{destination}+{mask}".format( 78 | urlbase=self.url_prefix, destination=destination, mask=mask.replace("/", "%2f")) 79 | -------------------------------------------------------------------------------- /acos_client/tests/unit/test_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | try: 18 | import unittest2 as unittest 19 | except ImportError: 20 | import unittest 21 | 22 | import acos_client 23 | 24 | 25 | class TestUtils(unittest.TestCase): 26 | 27 | def test_version(self): 28 | exp = (4, 1, 1, 0, 0, 0) 29 | tup = acos_client.utils.acos_version("4.1.1") 30 | self.assertEqual(tup, exp) 31 | 32 | exp = (4, 1, 1, 0, 2, 0) 33 | tup = acos_client.utils.acos_version("4.1.1-P2") 34 | self.assertEqual(tup, exp) 35 | 36 | exp = (4, 1, 1, 0, 2, 0) 37 | tup = acos_client.utils.acos_version("4.1.1-p2") 38 | self.assertEqual(tup, exp) 39 | 40 | exp = (4, 1, 4, 1, 2, 0) 41 | tup = acos_client.utils.acos_version("4.1.4-GR1-P2") 42 | self.assertEqual(tup, exp) 43 | 44 | exp = (4, 1, 4, 1, 3, 4) 45 | tup = acos_client.utils.acos_version("4.1.4-gr1-p3-sp4") 46 | self.assertEqual(tup, exp) 47 | 48 | exp = (4, 1, 4, 1, 3, 4) 49 | tup = acos_client.utils.acos_version("4.1.4-GR1-P3-SP4") 50 | self.assertEqual(tup, exp) 51 | 52 | exp = (5, 2, 0, 0, 0, 0) 53 | tup = acos_client.utils.acos_version("5.2.0") 54 | self.assertEqual(tup, exp) 55 | 56 | def test_version_cmp(self): 57 | rt = acos_client.utils.acos_version_cmp("5.2.0", "4.2.0") 58 | self.assertGreater(rt, 0) 59 | 60 | rt = acos_client.utils.acos_version_cmp("5.3.0", "5.2.0") 61 | self.assertGreater(rt, 0) 62 | 63 | rt = acos_client.utils.acos_version_cmp("5.2.0", "5.2.0") 64 | self.assertEqual(rt, 0) 65 | 66 | rt = acos_client.utils.acos_version_cmp("5.2.1", "5.2.0") 67 | self.assertGreater(rt, 0) 68 | 69 | rt = acos_client.utils.acos_version_cmp("5.2.1-P1", "5.2.1") 70 | self.assertGreater(rt, 0) 71 | 72 | rt = acos_client.utils.acos_version_cmp("5.2.1-GR1-P1", "5.2.1-GR1") 73 | self.assertGreater(rt, 0) 74 | 75 | rt = acos_client.utils.acos_version_cmp("5.2.1-GR1-P3-SP1", "5.2.1-GR1-P3") 76 | self.assertGreater(rt, 0) 77 | 78 | # case insensitive 79 | rt = acos_client.utils.acos_version_cmp("5.2.1-GR1-p1", "5.2.1-GR1") 80 | self.assertGreater(rt, 0) 81 | 82 | rt = acos_client.utils.acos_version_cmp("5.2.1-GR1-P3-SP1", "5.2.1-gr1-p3-sp1") 83 | self.assertEqual(rt, 0) 84 | -------------------------------------------------------------------------------- /acos_client/v30/sflow.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016, A10 Networks, All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client import errors as acos_errors 18 | from acos_client.v30 import base 19 | 20 | 21 | class SFlow(base.BaseV30): 22 | 23 | url_prefix = '/sflow/' 24 | 25 | @property 26 | def collector(self): 27 | return SFlowCollector(self.client) 28 | 29 | @property 30 | def setting(self): 31 | return SFlowSetting(self.client) 32 | 33 | @property 34 | def polling(self): 35 | return SFlowPolling(self.client) 36 | 37 | 38 | class SFlowSetting(base.BaseV30): 39 | url_prefix = "/sflow/setting" 40 | 41 | def create(self, max_header, source_ip_use_mgmt, 42 | packet_sampling_rate, counter_polling_interval, **kwargs): 43 | params = { 44 | "setting": { 45 | # "max-header": max_header, 46 | # "source-ip-use-mgmt": int(source_ip_use_mgmt), 47 | # "packet-sampling-rate": packet_sampling_rate, 48 | "counter-polling-interval": counter_polling_interval 49 | } 50 | } 51 | 52 | return self._post(self.url_prefix, params, **kwargs) 53 | 54 | def get(self): 55 | return self._get(self.url_prefix) 56 | 57 | 58 | class SFlowCollectorIP(base.BaseV30): 59 | url_prefix = "/sflow/collector/ip" 60 | 61 | def create(self, ip_address, port, **kwargs): 62 | params = { 63 | "ip": 64 | [{ 65 | "addr": ip_address, 66 | "port": int(port) 67 | }] 68 | 69 | } 70 | 71 | return self._post(self.url_prefix, params, **kwargs) 72 | 73 | def get(self, ip_address, port, **kwargs): 74 | url = "{0}/{1}+{2}".format(self.url_prefix, ip_address, port) 75 | return self._get(url, **kwargs) 76 | 77 | 78 | class SFlowCollector(base.BaseV30): 79 | @property 80 | def ip(self): 81 | return SFlowCollectorIP(self.client) 82 | 83 | 84 | class SFlowPolling(base.BaseV30): 85 | url_prefix = "/sflow/polling" 86 | 87 | def create(self, http_counter=False, **kwargs): 88 | params = { 89 | "polling": { 90 | "http-counter": http_counter 91 | } 92 | } 93 | try: 94 | return self._post(self.url_prefix, params, **kwargs) 95 | except acos_errors.Exists: 96 | pass 97 | 98 | def get(self, **kwargs): 99 | return self._get(self.url_prefix, **kwargs) 100 | -------------------------------------------------------------------------------- /acos_client/v30/slb/port.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | from acos_client.v30 import base 16 | 17 | 18 | class Port(base.BaseV30): 19 | 20 | url_base_tmpl = "/slb/server/{server}/port/" 21 | url_port_tmpl = "{port}+{protocol}/" 22 | 23 | def create(self, server_name, port, protocol, max_retries=None, timeout=None, 24 | conn_resume=None, conn_limit=None, stats_data_action="stats-data-enable", 25 | weight=1, range=0, action="enable", **kwargs): 26 | url = self.url_base_tmpl.format(server=server_name) 27 | params = self._set(server_name, port, protocol, conn_resume=conn_resume, conn_limit=conn_limit, 28 | stats_data_action=stats_data_action, weight=weight, range=range, action=action) 29 | return self._post(url, params, max_retries=max_retries, timeout=timeout, axapi_args=kwargs) 30 | 31 | def update(self, server_name, port, protocol, max_retries=None, timeout=None, 32 | conn_resume=None, conn_limit=None, stats_data_action="stats-data-enable", 33 | weight=1, range=0, action="enable", **kwargs): 34 | url = self.url_base_tmpl.format(server=server_name) 35 | url += self.url_port_tmpl.format(port=port, protocol=protocol) 36 | params = self._set(server_name, port, protocol, conn_resume=conn_resume, conn_limit=conn_limit, 37 | stats_data_action=stats_data_action, weight=weight, range=range, action=action) 38 | return self._put(url, params, max_retries=max_retries, timeout=timeout, axapi_args=kwargs) 39 | 40 | def delete(self, server_name, port, protocol, **kwargs): 41 | url = (self.url_base_tmpl + self.url_port_tmpl).format(server=server_name, 42 | port=port, 43 | protocol=protocol) 44 | 45 | return self._delete(url) 46 | 47 | def _set(self, server_name, port, protocol, conn_resume=None, conn_limit=None, 48 | stats_data_action="stats-data-enable", weight=1, range=0, action="enable"): 49 | params = { 50 | "port": { 51 | "stats-data-action": stats_data_action, 52 | "weight": weight, 53 | "port-number": port, 54 | "range": range, 55 | "action": action, 56 | "protocol": protocol 57 | } 58 | } 59 | 60 | if conn_resume: 61 | params['port']['conn-resume'] = conn_resume 62 | 63 | if conn_limit: 64 | params['port']['conn-limit'] = conn_limit 65 | 66 | return params 67 | -------------------------------------------------------------------------------- /acos_client/v21/system.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import six 18 | 19 | from acos_client import multipart 20 | from acos_client.v21.action import Action 21 | from acos_client.v21.admin import Admin 22 | from acos_client.v21 import base 23 | from acos_client.v21.config_file import ConfigFile 24 | from acos_client.v21.device_info import DeviceInfo 25 | from acos_client.v21.log import Log 26 | from acos_client.v21.partition import Partition 27 | 28 | 29 | class System(base.BaseV21): 30 | def backup(self, **kwargs): 31 | return self._get("system.backup", **kwargs) 32 | 33 | def restore(self, name, data, **kwargs): 34 | m = multipart.Multipart() 35 | m.file(name="restore", filename=name, value=data) 36 | ct, payload = m.get() 37 | if six.PY3: 38 | buffer = memoryview 39 | kwargs.update(payload=buffer(payload), headers={'Content-type': ct}) 40 | return self._post("system.restore", **kwargs) 41 | 42 | def tech_download(self, **kwargs): 43 | return self._get("system.show_tech.download", **kwargs) 44 | 45 | def information(self): 46 | return self._get("system.information.get") 47 | 48 | def performance(self): 49 | return self._get("system.performance.get") 50 | 51 | @property 52 | def admin(self): 53 | return Admin(self.client) 54 | 55 | @property 56 | def device_info(self): 57 | return DeviceInfo(self.client) 58 | 59 | @property 60 | def action(self): 61 | return Action(self.client) 62 | 63 | @property 64 | def partition(self): 65 | return Partition(self.client) 66 | 67 | @property 68 | def config_file(self): 69 | return ConfigFile(self.client) 70 | 71 | @property 72 | def log(self): 73 | return Log(self.client) 74 | 75 | @property 76 | def banner(self): 77 | return self.Banner(self.client) 78 | 79 | class Banner(base.BaseV21): 80 | def get(self, **kwargs): 81 | return self._get('system.banner.get', **kwargs) 82 | 83 | def set(self, banner, **kwargs): 84 | params = {"banner": banner} 85 | return self._post('system.log.banner.set', params, **kwargs) 86 | 87 | @property 88 | def hostname(self): 89 | return self.Hostname(self.client) 90 | 91 | class Hostname(base.BaseV21): 92 | def get(self, **kwargs): 93 | return self._get('system.hostname.get', **kwargs) 94 | 95 | def set(self, hostname, **kwargs): 96 | params = {"hostname": hostname} 97 | return self._post('system.hostname.set', params, **kwargs) 98 | -------------------------------------------------------------------------------- /acos_client/v21/slb/service_group.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v21 import base 18 | from acos_client.v21.slb.member import Member 19 | 20 | 21 | class ServiceGroup(base.BaseV21): 22 | 23 | @property 24 | def member(self): 25 | return Member(self.client) 26 | 27 | # Valid LB methods 28 | ROUND_ROBIN = 0 29 | WEIGHTED_ROUND_ROBIN = 1 30 | LEAST_CONNECTION = 2 31 | WEIGHTED_LEAST_CONNECTION = 3 32 | LEAST_CONNECTION_ON_SERVICE_PORT = 4 33 | WEIGHTED_LEAST_CONNECTION_ON_SERVICE_PORT = 5 34 | FAST_RESPONSE_TIME = 6 35 | LEAST_REQUEST = 7 36 | STRICT_ROUND_ROBIN = 8 37 | STATELESS_SOURCE_IP_HASH = 9 38 | STATELESS_SOURCE_IP_HASH_ONLY = 10 39 | STATELESS_DESTINATION_IP_HASH = 11 40 | STATELESS_SOURCE_DESTINATION_IP_HASH = 12 41 | STATELESS_PER_PACKET_ROUND_ROBIN = 13 42 | SOURCE_IP_HASH_ONLY = 14 43 | SOURCE_IP_HASH = 15 44 | DESTINATION_IP_HASH_ONLY = 16 45 | DESTINATION_IP_HASH = 17 46 | 47 | # Valid protocols 48 | TCP = 2 49 | UDP = 3 50 | 51 | def _set(self, action, name, protocol=None, lb_method=None, hm_name=None, 52 | **kwargs): 53 | params = { 54 | "service_group": self.minimal_dict({ 55 | "name": name, 56 | "protocol": protocol, 57 | "lb_method": lb_method, 58 | "health_monitor": hm_name 59 | }) 60 | } 61 | return self._post(action, params, **kwargs) 62 | 63 | def all(self, **kwargs): 64 | return self._get('slb.service_group.getAll', **kwargs) 65 | 66 | def all_delete(self, **kwargs): 67 | return self._get('slb.service_group.deleteAll', **kwargs) 68 | 69 | def all_stats(self, **kwargs): 70 | return self._get("slb.service_group.fetchAllStatistics", **kwargs) 71 | 72 | def create(self, name, protocol=TCP, lb_method=ROUND_ROBIN, **kwargs): 73 | return self._set("slb.service_group.create", name, protocol, lb_method, **kwargs) 74 | 75 | def delete(self, name, **kwargs): 76 | return self._post("slb.service_group.delete", {'name': name}, **kwargs) 77 | 78 | def get(self, name, **kwargs): 79 | return self._post("slb.service_group.search", {'name': name}, **kwargs) 80 | 81 | def stats(self, name, **kwargs): 82 | return self._post("slb.service_group.fetchStatistics", {"name": name}, **kwargs) 83 | 84 | def update(self, name, protocol=None, lb_method=None, health_monitor=None, **kwargs): 85 | return self._set( 86 | "slb.service_group.update", name, protocol, lb_method, health_monitor, **kwargs 87 | ) 88 | -------------------------------------------------------------------------------- /acos_client/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | 16 | class RequiredAttributeNotSpecified(Exception): 17 | 18 | def __init__(self, url, attribute, requires=[]): 19 | required_str = str(requires).strip("[]") 20 | self.message = ("The attribute {attribute} requires that {requires}" 21 | "also be specified when querying " 22 | "the {url} endpoint.").format(url, attribute, required_str) 23 | super(RequiredAttributeNotSpecified, self).__init__(self.message) 24 | 25 | 26 | class ACOSException(Exception): 27 | def __init__(self, code=1, msg=''): 28 | self.code = code 29 | self.msg = msg 30 | super(ACOSException, self).__init__(msg) 31 | 32 | def __str__(self): 33 | return "%d %s" % (self.code, self.msg) 34 | 35 | 36 | class ACOSUnsupportedVersion(ACOSException): 37 | pass 38 | 39 | 40 | class ACOSUnknownError(ACOSException): 41 | pass 42 | 43 | 44 | class AddressSpecifiedIsInUse(ACOSException): 45 | pass 46 | 47 | 48 | class AuthenticationFailure(ACOSException): 49 | pass 50 | 51 | 52 | class InvalidSessionID(ACOSException): 53 | pass 54 | 55 | 56 | class Exists(ACOSException): 57 | pass 58 | 59 | 60 | class NotFound(ACOSException): 61 | pass 62 | 63 | 64 | class NoSuchServiceGroup(ACOSException): 65 | pass 66 | 67 | 68 | class NotImplemented(ACOSException): 69 | pass 70 | 71 | 72 | class InUse(ACOSException): 73 | pass 74 | 75 | 76 | class InvalidPartitionParameter(ACOSException): 77 | pass 78 | 79 | 80 | class MemoryFault(ACOSException): 81 | pass 82 | 83 | 84 | class InvalidParameter(ACOSException): 85 | pass 86 | 87 | 88 | class OutOfPartitions(ACOSException): 89 | pass 90 | 91 | 92 | class PartitionIdExists(ACOSException): 93 | pass 94 | 95 | 96 | class HMMissingHttpPassive(ACOSException): 97 | pass 98 | 99 | 100 | class AxapiJsonFormatError(ACOSException): 101 | pass 102 | 103 | 104 | class ConfigManagerNotReady(ACOSException): 105 | pass 106 | 107 | 108 | class DhcpAcquireFailed(ACOSException): 109 | pass 110 | 111 | 112 | class InvalidInteger(ACOSException): 113 | pass 114 | 115 | 116 | class CertificateParsingFailed(ACOSException): 117 | pass 118 | 119 | 120 | class KeyParsingFailed(ACOSException): 121 | pass 122 | 123 | 124 | class FeatureNotSupported(ACOSException): 125 | pass 126 | 127 | 128 | class ACOSSystemNotReady(ACOSException): 129 | pass 130 | 131 | 132 | class ACOSSystemIsBusy(ACOSException): 133 | pass 134 | 135 | 136 | class LicenseOptionNotAllowed(ACOSException): 137 | pass 138 | -------------------------------------------------------------------------------- /acos_client/v21/slb/hm.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client import errors as acos_errors 18 | from acos_client.v21 import base 19 | 20 | 21 | class HealthMonitor(base.BaseV21): 22 | 23 | # Valid types 24 | ICMP = 0 25 | TCP = 1 26 | HTTP = 3 27 | HTTPS = 4 28 | 29 | def get(self, name, **kwargs): 30 | return self._post("slb.hm.search", {"name": name}, **kwargs) 31 | 32 | def _set(self, action, name, mon_type, interval, timeout, max_retries, 33 | method=None, url=None, expect_code=None, port=None, **kwargs): 34 | defs = { 35 | self.HTTP: { 36 | 'protocol': 'http', 37 | 'port': 80 38 | }, 39 | self.HTTPS: { 40 | 'protocol': 'https', 41 | 'port': 443 42 | }, 43 | self.ICMP: { 44 | 'protocol': 'icmp', 45 | }, 46 | self.TCP: { 47 | 'protocol': 'tcp', 48 | 'port': 80 49 | } 50 | } 51 | params = { 52 | 'retry': max_retries, 53 | 'name': name, 54 | 'consec_pass_reqd': max_retries, 55 | 'interval': interval, 56 | 'timeout': timeout, 57 | 'disable_after_down': 0, 58 | 'type': mon_type, 59 | } 60 | if mon_type in defs: 61 | params[defs[mon_type]['protocol']] = { 62 | 'url': "%s %s" % (method, url), 63 | 'expect_code': expect_code, 64 | } 65 | n = port or defs[mon_type].get('port') 66 | if n: 67 | params[defs[mon_type]['protocol']]['port'] = n 68 | try: 69 | self._post(action, params, **kwargs) 70 | except acos_errors.HMMissingHttpPassive: 71 | # Some version of AxAPI 2.1 require this arg 72 | params[defs[mon_type]['protocol']]['passive'] = 0 73 | self._post(action, params, **kwargs) 74 | 75 | def create(self, name, mon_type, interval, timeout, max_retries, 76 | method=None, url=None, expect_code=None, port=None, **kwargs): 77 | self._set("slb.hm.create", name, mon_type, interval, timeout, 78 | max_retries, method, url, expect_code, port, **kwargs) 79 | 80 | def update(self, name, mon_type, interval, timeout, max_retries, 81 | method=None, url=None, expect_code=None, port=None, **kwargs): 82 | self._set("slb.hm.update", name, mon_type, interval, timeout, 83 | max_retries, method, url, expect_code, port, **kwargs) 84 | 85 | def delete(self, name, **kwargs): 86 | self._post("slb.hm.delete", {"name": name}, **kwargs) 87 | -------------------------------------------------------------------------------- /acos_client/v30/slb/template/l7.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015, Tobit Raff, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | import six 17 | 18 | 19 | from acos_client import errors as acos_errors 20 | from acos_client.v30 import base 21 | 22 | 23 | class BaseL7(base.BaseV30): 24 | 25 | def get(self, name, **kwargs): 26 | return self._get(self.url_prefix + name, **kwargs) 27 | 28 | def exists(self, name): 29 | try: 30 | self.get(name) 31 | return True 32 | except acos_errors.NotFound: 33 | return False 34 | 35 | def _set(self, name, insert_client_ip=0, insert_client_ip_header_name="", client_ip_hdr_replace=0, 36 | request_header_insert_list=[], response_header_insert_list=[], update=False, 37 | **kwargs): 38 | # Unimplemented options: 39 | # Everything except for insert_client_ip and request header insert. 40 | 41 | obj_params = { 42 | "name": name, 43 | "insert-client-ip": insert_client_ip, 44 | "insert-client-ip-header-name": insert_client_ip_header_name, 45 | "client-ip-hdr-replace": client_ip_hdr_replace, 46 | "request-header-insert-list": request_header_insert_list, 47 | "response-header-insert-list": response_header_insert_list 48 | } 49 | 50 | params = {'%s' % self.prefix: {}} 51 | for key, val in six.iteritems(obj_params): 52 | # Filter out invalid, or unset keys 53 | if val != "": 54 | params['%s' % self.prefix][key] = val 55 | if not update: 56 | name = '' 57 | self._post(self.url_prefix + name, params, **kwargs) 58 | 59 | def create(self, name, insert_client_ip=False, insert_client_ip_header_name="", 60 | client_ip_hdr_replace=0, request_header_insert_list=[], response_header_insert_list=[], 61 | **kwargs): 62 | if self.exists(name): 63 | raise acos_errors.Exists 64 | 65 | self._set(name, insert_client_ip, insert_client_ip_header_name, client_ip_hdr_replace, 66 | request_header_insert_list, response_header_insert_list, **kwargs) 67 | 68 | def update(self, name, insert_client_ip=False, insert_client_ip_header_name="", 69 | client_ip_hdr_replace=0, request_header_insert_list=[], response_header_insert_list=[], 70 | **kwargs): 71 | self._set(name, insert_client_ip, insert_client_ip_header_name, client_ip_hdr_replace, 72 | request_header_insert_list, response_header_insert_list, update=True, **kwargs) 73 | 74 | def delete(self, name, **kwargs): 75 | self._delete(self.url_prefix + name, **kwargs) 76 | 77 | 78 | class HTTPTemplate(BaseL7): 79 | 80 | url_prefix = '/slb/template/http/' 81 | prefix = 'http' 82 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v21/test_system.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Doug Wiegley, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from __future__ import absolute_import 16 | from __future__ import unicode_literals 17 | 18 | try: 19 | import unittest2 as unittest 20 | except ImportError: 21 | import unittest 22 | 23 | from acos_client import client 24 | import responses 25 | 26 | 27 | HOSTNAME = 'fake_a10' 28 | BASE_URL = "https://{}:443/services/rest/v2.1/?format=json&method=".format(HOSTNAME) 29 | AUTH_URL = "{}authenticate".format(BASE_URL) 30 | SYS_INFO_URL = '{}system.information.get&session_id={}'.format(BASE_URL, 'foobar') 31 | SYS_WRITE_MEM_URL = '{}system.action.write_memory&session_id={}'.format(BASE_URL, 'foobar') 32 | 33 | 34 | class TestHighAvailability(unittest.TestCase): 35 | 36 | def setUp(self): 37 | self.client = client.Client(HOSTNAME, '21', 'fake_username', 'fake_password') 38 | 39 | @responses.activate 40 | def test_system_information(self): 41 | responses.add(responses.POST, AUTH_URL, json={'session_id': 'foobar'}) 42 | json_response = { 43 | 'system_information': { 44 | 'advanced_core_os_on_compact_flash1': 'No Software', 45 | 'advanced_core_os_on_compact_flash2': 'No Software', 46 | 'advanced_core_os_on_harddisk1': '2.7.1-P3-AWS(build: 4)', 47 | 'advanced_core_os_on_harddisk2': '2.7.1-P3-AWS(build: 4)', 48 | 'aflex_engine_version': '2.0.0', 49 | 'axapi_version': '2.1', 50 | 'current_time': '03:25:47 IST Tue Jul 1 2014', 51 | 'firmware_version': 'N/A', 52 | 'last_config_saved': '06:25:26 GMT Sat Dec 28 2013', 53 | 'serial_number': 'N/A', 54 | 'software_version': '2.7.1-P3-AWS(build: 4)', 55 | 'startup_mode': 'hard disk primary', 56 | 'technical_support': 'www.a10networks.com/support ' 57 | } 58 | } 59 | responses.add(responses.GET, SYS_INFO_URL, json=json_response, status=200) 60 | 61 | resp = self.client.system.information() 62 | 63 | self.assertEqual(resp, json_response) 64 | self.assertEqual(len(responses.calls), 2) 65 | self.assertEqual(responses.calls[1].request.method, responses.GET) 66 | self.assertEqual(responses.calls[1].request.url, SYS_INFO_URL) 67 | 68 | @responses.activate 69 | def test_system_write_memory(self): 70 | responses.add(responses.POST, AUTH_URL, json={'session_id': 'foobar'}) 71 | json_response = {'response': {'status': 'OK'}} 72 | responses.add(responses.GET, SYS_WRITE_MEM_URL, json=json_response, status=200) 73 | 74 | resp = self.client.system.action.write_memory() 75 | 76 | self.assertIsNone(resp) 77 | self.assertEqual(len(responses.calls), 2) 78 | self.assertEqual(responses.calls[1].request.method, responses.GET) 79 | self.assertEqual(responses.calls[1].request.url, SYS_WRITE_MEM_URL) 80 | -------------------------------------------------------------------------------- /acos_client/v21/log.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | from acos_client.v21 import base 16 | 17 | 18 | class Log(base.BaseV21): 19 | 20 | def set(self, sys_log, **kwargs): 21 | params = {"sys_log": sys_log} 22 | return self._post("system.log.set", params, **kwargs) 23 | 24 | def get(self, **kwargs): 25 | return self._get("system.log.get", **kwargs) 26 | 27 | def clear(self, sys_log, **kwargs): 28 | return self._post("system.log.clear", **kwargs) 29 | 30 | def download(self, **kwargs): 31 | return self._get('system.log.download', **kwargs) 32 | 33 | def backup(self, **kwargs): 34 | return self._post('system.log.backup', **kwargs) 35 | 36 | @property 37 | def level(self): 38 | return self.Level(self.client) 39 | 40 | @property 41 | def server(self): 42 | return self.Server(self.client) 43 | 44 | @property 45 | def buffer(self): 46 | return self.Buffer(self.client) 47 | 48 | @property 49 | def smtp(self): 50 | return self.Smtp(self.client) 51 | 52 | @property 53 | def audit(self): 54 | return self.Audit(self.client) 55 | 56 | class Level(base.BaseV21): 57 | def get(self, **kwargs): 58 | return self._get('system.log.level.get', **kwargs) 59 | 60 | def set(self, log_level, **kwargs): 61 | params = {"log_level": log_level} 62 | return self._post('system.log.level.set', params, **kwargs) 63 | 64 | class Server(base.BaseV21): 65 | def get(self, **kwargs): 66 | return self._get('system.log.server.get', **kwargs) 67 | 68 | def set(self, log_server, **kwargs): 69 | params = {"log_server": log_server} 70 | return self._post('system.log.server.set', params, **kwargs) 71 | 72 | class Buffer(base.BaseV21): 73 | def get(self, **kwargs): 74 | return self._get('system.log.buffer.get', **kwargs) 75 | 76 | def set(self, buff_size, **kwargs): 77 | params = {"buffer_size": buff_size} 78 | return self._post('system.log.buffer.set', params, **kwargs) 79 | 80 | class Smtp(base.BaseV21): 81 | def get(self, **kwargs): 82 | return self._get('system.log.smtp.get', **kwargs) 83 | 84 | def set(self, smtp, **kwargs): 85 | params = {"smtp": smtp} 86 | return self._post('system.log.smtp.set', params, **kwargs) 87 | 88 | class Audit(base.BaseV21): 89 | def get(self, **kwargs): 90 | return self._get('system.log.audit.get', **kwargs) 91 | 92 | def set(self, audit, **kwargs): 93 | params = {"audit": audit} 94 | return self._post('system.log.audit.set', params, **kwargs) 95 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v30/test_dns.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2016, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | try: 18 | import unittest 19 | from unittest import mock 20 | except ImportError: 21 | import mock 22 | import unittest2 as unittest 23 | 24 | from acos_client.v30 import dns 25 | 26 | 27 | class TestDns(unittest.TestCase): 28 | def setUp(self): 29 | self.client = mock.MagicMock() 30 | self.target = dns.DNS(self.client) 31 | self.url_prefix = "/axapi/v3/ip/dns/" 32 | 33 | def test_primary_ipv4(self): 34 | expected = '192.0.2.4' 35 | self.target.set(primary=expected) 36 | 37 | expected_payload = {'primary': {'ip-v4-addr': expected}} 38 | 39 | self.client.http.request.assert_called_with("POST", self.url_prefix + 'primary', 40 | expected_payload, mock.ANY, axapi_args=None, 41 | max_retries=None, timeout=mock.ANY) 42 | 43 | def test_primary_ipv6(self): 44 | expected = '0:0:0:0:0:FFFF:129.144.52.38' 45 | self.target.set(primary=expected) 46 | 47 | expected_payload = {'primary': {'ip-v6-addr': expected}} 48 | 49 | self.client.http.request.assert_called_with("POST", self.url_prefix + 'primary', 50 | expected_payload, mock.ANY, axapi_args=None, 51 | max_retries=None, timeout=mock.ANY) 52 | 53 | def test_secondary_ipv4(self): 54 | expected = '192.0.2.5' 55 | self.target.set(secondary=expected) 56 | 57 | expected_payload = {'secondary': {'ip-v4-addr': expected}} 58 | 59 | self.client.http.request.assert_called_with("POST", self.url_prefix + 'secondary', 60 | expected_payload, mock.ANY, axapi_args=None, 61 | max_retries=None, timeout=mock.ANY) 62 | 63 | def test_secondary_ipv6(self): 64 | expected = '0:0:0:0:0:FFFF:129.144.52.39' 65 | self.target.set(secondary=expected) 66 | 67 | expected_payload = {'secondary': {'ip-v6-addr': expected}} 68 | 69 | self.client.http.request.assert_called_with("POST", self.url_prefix + 'secondary', 70 | expected_payload, mock.ANY, axapi_args=None, 71 | max_retries=None, timeout=mock.ANY) 72 | 73 | def test_suffix(self): 74 | expected = 'example.com' 75 | self.target.set(suffix=expected) 76 | 77 | expected_payload = {'suffix': {'domain-name': expected}} 78 | 79 | self.client.http.request.assert_called_with("POST", self.url_prefix + 'suffix', 80 | expected_payload, mock.ANY, axapi_args=None, 81 | max_retries=None, timeout=mock.ANY) 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ACOS Client 2 | 3 | ## Table of Contents 4 | 1. [Supported Versions](#Supported-Versions) 5 | 6 | 2. [Installation for ACOSv4.1.4](#Installation-ACOSv4.1.4) 7 | 8 | 3. [Installation for ACOSv4.1.1](#Installation-ACOSv4.1.1) 9 | 10 | 4. [Example usage information](#Usage) 11 | 12 | 5. [Contributing & Testing](#Contributing) 13 | 14 | 6. [Issues and Inquiries](#Issues-and-Inquiries) 15 | 16 | 7. [Helpful Links](#Helpful-links) 17 | 18 | 19 | ## Supported Versions 20 | 21 | ``` 22 | | ACOS Version | AXAPI Version | ACOS Client Version | Status | 23 | | 2.7.1† | 2 | >=0.1.0,<0.3.0 | end-of-life | 24 | | 2.7.2 | 2 | >=0.1.0,<0.3.0 | end-of-life | 25 | | 4.0.0 | 3 | >=1.4.6,<1.5.0 | end-of-life | 26 | | 4.1.1 | 3 | >=1.5.0,<2.0.0 | end-of-life | 27 | | 4.1.4 GR1-P2 | 3 | >=2.0.0,<2.4.0 | end-of-life | 28 | | 4.1.4 | 3 | >=2.4.0 | end-of-life | 29 | | 4.1.4 GR1-P5 | 3 | >=2.6.0 | Maintenance | 30 | | 5.2.1 | 3 | >=2.6.0 | Maintenance | 31 | | 5.2.1-p1 | 3 | >=2.7.0 | Maintenance | 32 | | 5.2.1-p2 | 3 | >=2.9.0 | Maintenance | 33 | | 5.2.1-p2 | 3 | >=2.9.1 | Maintenance | 34 | | 5.2.1-p2 | 3 | >=2.10.0 | Maintenance | 35 | ``` 36 | 37 | †Works only when not using partitioning 38 | 39 | ## Installation 40 | 41 | ### Install using pip 42 | 43 | ```sh 44 | $ pip install acos-client>=2.9.0 45 | ``` 46 | 47 | ### Install from source 48 | 49 | ```sh 50 | $ git clone https://github.com/a10networks/acos-client.git 51 | $ cd acos-client 52 | $ git checkout stable/stein 53 | $ pip install -e . 54 | ``` 55 | 56 | ## Usage 57 | 58 | ```python 59 | c = acos_client.Client('somehost.example.com', acos_client.AXAPI_30, 'admin', 'password') 60 | ``` 61 | 62 | #### Example setting up an SLB: 63 | 64 | ```python 65 | import acos_client as acos 66 | 67 | c = acos.Client('1.2.3.4', acos.AXAPI_30, 'admin', 'password') 68 | c.slb.server.create('s1', '1.1.1.1') 69 | c.slb.server.create('s2', '1.1.1.2') 70 | c.slb.service_group.create('pool1', c.slb.service_group.TCP, c.slb.service_group.ROUND_ROBIN) 71 | c.slb.virtual_server.create('vip1', '1.1.1.3') 72 | c.slb.hm.create('hm1', c.slb.hm.HTTP, 5, 5, 5, 'GET', '/', '200', 80) 73 | c.slb.service_group.update('pool1', health_monitor='hm1') 74 | c.slb.service_group.member.create('pool1', 's1', 80) 75 | c.slb.service_group.member.create('pool1', 's2', 80) 76 | ``` 77 | 78 | ## Contributing 79 | 80 | 1. Fork it 81 | 2. Create your feature branch (`git checkout -b my-new-feature`) 82 | 3. Commit your changes (`git commit -am 'Add some feature'`) 83 | 4. Push to the branch (`git push origin my-new-feature`) 84 | 5. Create new Pull Request 85 | 86 | ### Testing 87 | 88 | This project uses [tox](https://pypi.python.org/pypi/tox) for testing. To run 89 | the test suite simply: 90 | 91 | ```sh 92 | $ sudo pip install tox # use pip2 if using Arch Linux 93 | $ cd /path/to/acos_client 94 | $ tox 95 | ``` 96 | 97 | ## Issues and Inquiries 98 | For all issues, please send an email to support@a10networks.com 99 | 100 | 101 | ## Helpful links 102 | 103 | ### Improved speed 104 | pypy: [http://pypy.org/index.html](http://pypy.org/index.html) 105 | 106 | ### Old python versions 107 | Deadsnakes github: [https://github.com/deadsnakes](https://github.com/deadsnakes) 108 | Deadsnakes ppa: [https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa](https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa) 109 | -------------------------------------------------------------------------------- /acos_client/v30/vrrpa/blade_params.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016, A10 Networks 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from acos_client.v30 import base 16 | 17 | 18 | class BladeParameters(base.BaseV30): 19 | def __init__(self, client): 20 | super(BladeParameters, self).__init__(client) 21 | self.base_url = "/vrrp-a/vrid/{0}/blade-parameters" 22 | self.interfaces = {'interface': []} 23 | self.gateways = { 24 | 'gateway': { 25 | 'ipv4-gateway-list': [], 26 | 'ipv6-gateway-list': [] 27 | } 28 | } 29 | 30 | def _build_params(self, priority=None, **kwargs): 31 | rv = {'blade-parameters': {}} 32 | if priority: 33 | priority = priority if priority in range(1, 256) else 150 34 | rv['blade-parameters']['priority'] = priority 35 | 36 | if self.interfaces['interface']: 37 | rv['blade-parameters']['tracking-options'] = self.interfaces 38 | 39 | if self.gateways['gateway']['ipv4-gateway-list']: 40 | if rv['blade-parameters'].get('tracking-options'): 41 | rv['blade-parameters']['tracking-options'].update(self.gateways) 42 | else: 43 | rv['blade-parameters']['tracking-options'] = self.gateways 44 | 45 | if self.gateways['gateway']['ipv6-gateway-list']: 46 | if rv['blade-parameters'].get('tracking-options'): 47 | if rv['blade-parameters']['tracking-options'].get('gateway'): 48 | rv['blade-parameters']['tracking-options']['gateway'].update(self.gateways) 49 | else: 50 | rv['blade-parameters']['tracking-options'] = self.gateways 51 | else: 52 | rv['blade-parameters']['tracking-options'] = self.gateways 53 | return rv 54 | 55 | def add_interface(self, ethernet=1, priority_cost=1): 56 | interface = { 57 | 'ethernet': ethernet, 58 | 'priority-cost': priority_cost 59 | } 60 | self.interfaces['interface'].append(interface) 61 | 62 | def add_ipv4gateway(self, ip_address, priority_cost=1): 63 | gateway = { 64 | 'ip-address': ip_address, 65 | 'priority-cost': priority_cost 66 | } 67 | self.gateways['gateway']['ipv4-gateway-list'].append(gateway) 68 | 69 | def add_ipv6gateway(self, ip_address, priority_cost=1): 70 | gateway = { 71 | 'ip-address': ip_address, 72 | 'priority-cost': priority_cost 73 | } 74 | self.gateways['gateway']['ipv6-gateway-list'].append(gateway) 75 | 76 | def get(self, vrid_val): 77 | return self._get(self.base_url.format(vrid_val)) 78 | 79 | def create(self, vrid_val, priority=None, **kwargs): 80 | payload = self._build_params(priority, **kwargs) 81 | self._post(self.base_url.format(vrid_val), payload) 82 | 83 | def update(self, vrid_val, priority=None, **kwargs): 84 | payload = self._build_params(priority, **kwargs) 85 | self._put(self.base_url.format(vrid_val), payload) 86 | 87 | def delete(self, vrid_val): 88 | return self._delete(self.base_url.format(vrid_val)) 89 | -------------------------------------------------------------------------------- /acos_client/v30/nat.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015, A10 Networks 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client import errors as acos_errors 18 | from acos_client.v30 import base 19 | 20 | 21 | class Nat(base.BaseV30): 22 | 23 | @property 24 | def pool(self): 25 | return self.Pool(self.client) 26 | 27 | @property 28 | def ipv6pool(self): 29 | return self.IPv6Pool(self.client) 30 | 31 | class Pool(base.BaseV30): 32 | url_prefix = "/ip/nat/pool/" 33 | 34 | def _set(self, name, start_ip, end_ip, mask, ip_rr=None, vrid=None, gateway=None): 35 | params = { 36 | "pool": self.minimal_dict( 37 | { 38 | 'pool-name': name, 39 | 'start-address': start_ip, 40 | 'end-address': end_ip, 41 | 'netmask': mask, 42 | } 43 | ), 44 | } 45 | 46 | if ip_rr: 47 | params["pool"]["ip-rr"] = ip_rr 48 | 49 | if vrid: 50 | params["pool"]["vrid"] = vrid 51 | 52 | if gateway: 53 | params["pool"]['gateway'] = gateway 54 | 55 | return params 56 | 57 | def get(self, name): 58 | return self._get(self.url_prefix + name) 59 | 60 | def try_get(self, name): 61 | try: 62 | return self.get(name) 63 | except acos_errors.NotFound: 64 | return None 65 | 66 | def exists(self, name): 67 | try: 68 | self.get(name) 69 | return True 70 | except acos_errors.NotFound: 71 | return False 72 | 73 | def all(self): 74 | return self._get(self.url_prefix) 75 | 76 | def create(self, pool_name, start_address, end_address, netmask, ip_rr=None, vrid=None, 77 | gateway=None, max_retries=None, timeout=None, **kwargs): 78 | if self.exists(pool_name): 79 | raise acos_errors.Exists 80 | params = self._set(pool_name, start_address, end_address, netmask, 81 | ip_rr=ip_rr, vrid=vrid, gateway=gateway) 82 | axapi_args = {'pool': kwargs} 83 | return self._post(self.url_prefix, params, max_retries=max_retries, 84 | timeout=timeout, axapi_args=axapi_args) 85 | 86 | def delete(self, name, **kwargs): 87 | self._delete(self.url_prefix + name) 88 | 89 | def stats(self, name='', max_retries=None, timeout=None, **kwargs): 90 | return self._get(self.url_prefix + name + '/stats', 91 | max_retries=max_retries, timeout=timeout, 92 | **kwargs) 93 | 94 | def all_stats(self, **kwargs): 95 | return self.stats() 96 | 97 | 98 | class IPv6Pool(Pool): 99 | def __init__(self, client): 100 | super().__init__(client) 101 | self.url_prefix = "/ipv6/nat/pool/" 102 | -------------------------------------------------------------------------------- /acos_client/v30/vlan.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016, A10 Networks 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client import errors as acos_errors 18 | from acos_client.v30 import base 19 | 20 | 21 | class Vlan(base.BaseV30): 22 | def __init__(self, client): 23 | super(Vlan, self).__init__(client) 24 | self.url_prefix = "/network/vlan" 25 | 26 | def _build_id_url(self, vlan_id): 27 | return "{0}/{1}".format(self.url_prefix, vlan_id) 28 | 29 | def get_list(self): 30 | return self._get(self.url_prefix) 31 | 32 | def create(self, vlan_id, name=None, shared_vlan=False, 33 | untagged_eths=[], untagged_trunks=[], 34 | tagged_eths=[], tagged_trunks=[], veth=False, 35 | lif=None): 36 | 37 | payload = { 38 | "vlan": self._build_payload( 39 | name, vlan_id, shared_vlan, untagged_eths, 40 | untagged_trunks, 41 | tagged_eths, tagged_trunks, 42 | veth, lif) 43 | } 44 | return self._post(self.url_prefix, payload) 45 | 46 | def get(self, vlan_id): 47 | return self._get(self._build_id_url(vlan_id)) 48 | 49 | def exists(self, vlan_id): 50 | try: 51 | self.get(vlan_id) 52 | return True 53 | except acos_errors.NotFound: 54 | return False 55 | 56 | def delete(self, vlan_id): 57 | return self._delete(self._build_id_url(vlan_id)) 58 | 59 | def _build_payload(self, name, vlan_id, shared_vlan, 60 | untagged_eths, untagged_trunks, 61 | tagged_eths, tagged_trunks, 62 | veth, lif): 63 | rv = { 64 | "vlan-num": vlan_id, 65 | } 66 | 67 | if name: 68 | rv["name"] = name 69 | 70 | if shared_vlan is True: 71 | rv["shared-vlan"] = shared_vlan 72 | 73 | if untagged_eths: 74 | rv.update(self._build_range_list("untagged-eth", untagged_eths, "untagged-ethernet")) 75 | 76 | if tagged_eths: 77 | rv.update(self._build_range_list("tagged-eth", tagged_eths, "tagged-ethernet")) 78 | 79 | if untagged_trunks: 80 | rv.update(self._build_range_list("untagged-trunk", untagged_trunks)) 81 | 82 | if tagged_trunks: 83 | rv.update(self._build_range_list("tagged-trunk", tagged_trunks)) 84 | 85 | if veth: 86 | rv["ve"] = vlan_id 87 | 88 | if lif: 89 | rv["untagged-lif"] = lif 90 | 91 | return rv 92 | 93 | def _build_range_list(self, prefix="", xlist=[], inconsistent_prefix=""): 94 | # Naive way of building this poorly-conceived API call 95 | rv = [] 96 | ekey_f = "{0}-list" 97 | rkey_f = "{0}-{1}" 98 | 99 | # Justification for snarky prefix 100 | fix_prefix = lambda: inconsistent_prefix if inconsistent_prefix else prefix 101 | 102 | for x in xlist: 103 | lm = {} 104 | lm[rkey_f.format(fix_prefix(), "start")] = x 105 | lm[rkey_f.format(fix_prefix(), "end")] = x 106 | rv.append(lm) 107 | 108 | return {ekey_f.format(prefix): rv} 109 | -------------------------------------------------------------------------------- /acos_client/v30/vrrpa/vrid.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016, A10 Networks 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from acos_client import errors as acos_errors 16 | from acos_client.v30 import base 17 | from acos_client.v30.vrrpa.blade_params import BladeParameters 18 | from collections import ChainMap 19 | 20 | 21 | class VRID(base.BaseV30): 22 | 23 | def __init__(self, client): 24 | super(VRID, self).__init__(client) 25 | self.client = client 26 | self.base_url = "/vrrp-a/vrid/" 27 | 28 | @property 29 | def blade(self): 30 | return BladeParameters(self.client) 31 | 32 | def get(self, vrid_val): 33 | return self._get(self.base_url + str(vrid_val)) 34 | 35 | def exists(self, vrid_val): 36 | try: 37 | self.get(vrid_val) 38 | return True 39 | except acos_errors.NotFound: 40 | return False 41 | 42 | def _build_params(self, vrid_val, threshold=None, disable=None, floating_ips=[], 43 | is_partition=False): 44 | vrid = {'vrid-val': vrid_val} 45 | vrid_floating_ips = None 46 | if floating_ips: 47 | if is_partition: 48 | ip_partition_list = [{'ip-address-partition': ip} for ip in floating_ips if not self._is_ipv6(ip)] 49 | vrid_floating_ips = { 50 | 'ip-address-part-cfg': ip_partition_list 51 | } 52 | ipv6_partition_list = [{'ipv6-address-partition': ip} for ip in floating_ips if self._is_ipv6(ip)] 53 | ipv6_vrid_floating_ips = { 54 | 'ipv6-address-part-cfg': ipv6_partition_list 55 | } 56 | else: 57 | ip_list = [{'ip-address': ip} for ip in floating_ips if not self._is_ipv6(ip)] 58 | vrid_floating_ips = { 59 | 'ip-address-cfg': ip_list 60 | } 61 | ipv6_list = [{'ipv6-address': ip} for ip in floating_ips if self._is_ipv6(ip)] 62 | ipv6_vrid_floating_ips = { 63 | 'ipv6-address-cfg': ipv6_list 64 | } 65 | vrid['floating-ip'] = dict(ChainMap(vrid_floating_ips, ipv6_vrid_floating_ips)) 66 | 67 | if threshold or disable: 68 | threshold = threshold if threshold in range(0, 256) else 1 69 | disable = disable if disable in [0, 1] else 0 70 | preempt = { 71 | 'threshold': threshold, 72 | 'disable': disable 73 | } 74 | vrid['preempt-mode'] = preempt 75 | 76 | payload = {'vrid': vrid} 77 | return payload 78 | 79 | def create(self, vrid_val, threshold=None, disable=None, floating_ips=[], is_partition=False): 80 | return self._post(self.base_url, self._build_params(vrid_val, threshold, disable, 81 | floating_ips, is_partition)) 82 | 83 | def update(self, vrid_val, threshold=None, disable=None, floating_ips=[], is_partition=False): 84 | return self._put(self.base_url + str(vrid_val), self._build_params(vrid_val, threshold, 85 | disable, floating_ips, 86 | is_partition)) 87 | 88 | def delete(self, vrid_val): 89 | return self._delete(self.base_url + str(vrid_val)) 90 | -------------------------------------------------------------------------------- /acos_client/v30/base.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import ipaddress 18 | import six 19 | import time 20 | 21 | from acos_client import errors as ae 22 | 23 | 24 | class BaseV30(object): 25 | 26 | def __init__(self, client): 27 | self.client = client 28 | self.http = client.http 29 | self.auth_header = {} 30 | 31 | def minimal_dict(self, my_dict, exclude=[]): 32 | return dict((k, v) for k, v in my_dict.items() if v is not None or k in exclude) 33 | 34 | def url(self, action): 35 | self.auth_header['Authorization'] = "A10 %s" % self.client.session.id 36 | return ("/axapi/v3" + action) 37 | 38 | def _request(self, method, action, params, retry_count=0, max_retries=None, 39 | timeout=None, axapi_args=None, **kwargs): 40 | if retry_count > 24: 41 | raise ae.ACOSUnknownError() 42 | 43 | try: 44 | return self.client.http.request(method, self.url(action), params, self.auth_header, 45 | max_retries=max_retries, timeout=timeout, 46 | axapi_args=axapi_args, **kwargs) 47 | except (ae.InvalidSessionID, ae.ConfigManagerNotReady) as e: 48 | if type(e) == ae.ConfigManagerNotReady: 49 | retry_limit = 24 50 | sleep_secs = 5 51 | else: 52 | retry_limit = 5 53 | sleep_secs = 1.0 54 | 55 | if retry_count < retry_limit: 56 | time.sleep(sleep_secs) 57 | try: 58 | p = self.client.current_partition 59 | self.client.session.close() 60 | self.client.partition.active(p) 61 | except Exception: 62 | pass 63 | return self._request(method, action, params, retry_count + 1, max_retries=max_retries, 64 | timeout=timeout, axapi_args=axapi_args, **kwargs) 65 | raise e 66 | 67 | def _get(self, action, params={}, max_retries=None, timeout=None, axapi_args=None, **kwargs): 68 | return self._request('GET', action, params, max_retries=max_retries, timeout=timeout, 69 | axapi_args=axapi_args, **kwargs) 70 | 71 | def _post(self, action, params={}, max_retries=None, timeout=None, axapi_args=None, **kwargs): 72 | return self._request('POST', action, params, max_retries=max_retries, timeout=timeout, 73 | axapi_args=axapi_args, **kwargs) 74 | 75 | def _put(self, action, params={}, max_retries=None, timeout=None, axapi_args=None, **kwargs): 76 | return self._request('PUT', action, params, max_retries=max_retries, timeout=timeout, 77 | axapi_args=axapi_args, **kwargs) 78 | 79 | def _delete(self, action, params={}, max_retries=None, timeout=None, axapi_args=None, **kwargs): 80 | return self._request('DELETE', action, params, max_retries=max_retries, timeout=timeout, 81 | axapi_args=axapi_args, **kwargs) 82 | 83 | def _is_ipv6(self, ip_address): 84 | validated_ip_address = ipaddress.ip_address(six.text_type(ip_address)) 85 | return isinstance(validated_ip_address, ipaddress.IPv6Address) 86 | -------------------------------------------------------------------------------- /acos_client/v30/partition.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | import random 18 | import six 19 | import time 20 | 21 | from acos_client import errors as acos_errors 22 | from acos_client.v30 import base 23 | 24 | 25 | class Partition(base.BaseV30): 26 | 27 | def available(self): 28 | return self._get('/partition-available-id/oper/') 29 | 30 | def all(self): 31 | return self._get('/partition-all/oper') 32 | 33 | def get(self, name): 34 | z = self.all() 35 | if not z: 36 | raise acos_errors.NotFound() 37 | # There is no partition-list member if there are no partitions 38 | for p in z['partition-all']['oper'].get('partition-list', {}): 39 | if p['partition-name'] == name: 40 | return p 41 | raise acos_errors.NotFound() 42 | 43 | def old_get(self, name): 44 | return self._get('/partition/' + name) 45 | 46 | def exists(self, name): 47 | if name == 'shared': 48 | return True 49 | try: 50 | self.get(name) 51 | return True 52 | except acos_errors.NotFound: 53 | return False 54 | 55 | def active(self, name='shared'): 56 | if self.client.current_partition != name: 57 | self._post("/active-partition/" + name) 58 | self.client.current_partition = name 59 | 60 | def _next_available_id(self): 61 | a = self.available() 62 | if a is None: 63 | raise acos_errors.OutOfPartitions() 64 | 65 | z = a['partition-available-id']['oper']['range-list'][0]['start'] 66 | return int(z) 67 | 68 | def _create(self, name, partition_id, application_type=None): 69 | params = { 70 | "partition": { 71 | "partition-name": name, 72 | "id": partition_id, 73 | } 74 | } 75 | 76 | if application_type: 77 | params['partition']['application-type'] = application_type 78 | 79 | self._post("/partition", params) 80 | 81 | def create(self, name, application_type=None): 82 | if name == 'shared': 83 | return 84 | 85 | if self.exists(name): 86 | raise acos_errors.Exists 87 | 88 | # For concurrency's sake, since we have to lookup the id and then 89 | # set it, loop if we get an exists error. 90 | for i in six.moves.range(1, 1000): 91 | try: 92 | self._create(name, self._next_available_id(), application_type) 93 | break 94 | except acos_errors.PartitionIdExists: 95 | time.sleep(0.05 + random.random() / 100) 96 | 97 | def delete(self, name): 98 | if name == 'shared': 99 | return 100 | 101 | self.client.session.close() 102 | try: 103 | self._delete("/partition/" + name) 104 | except acos_errors.NotFound: 105 | pass 106 | 107 | self.client.session.close() 108 | x = self.get(name) 109 | p = { 110 | 'partition': { 111 | 'partition-name': name, 112 | 'id': x['partition-id'] 113 | } 114 | } 115 | self._post("/delete/partition", p) 116 | 117 | self.client.session.close() 118 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v30/test_port.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | from __future__ import absolute_import 13 | from __future__ import unicode_literals 14 | 15 | try: 16 | import unittest 17 | from unittest import mock 18 | except ImportError: 19 | import mock 20 | import unittest2 as unittest 21 | 22 | from acos_client.v30.slb import port 23 | 24 | 25 | class TestPort(unittest.TestCase): 26 | def setUp(self): 27 | self.client = mock.MagicMock() 28 | self.port = port.Port(self.client) 29 | 30 | # common test parameter(s) throughout all test-cases 31 | self._server_name = 'test_server' 32 | 33 | def test_create_port(self): 34 | expected = { 35 | 'port': { 36 | "stats-data-action": "stats-data-enable", 37 | "weight": 1, 38 | "port-number": 80, 39 | "range": 0, 40 | "action": "enable", 41 | "protocol": 'tcp' 42 | } 43 | } 44 | self.port.create('test_server', 80, 'tcp') 45 | 46 | ((method, url, params, header), kwargs) = self.client.http.request.call_args 47 | 48 | self.assertEqual(method, 'POST') 49 | self.assertEqual(url, '/axapi/v3/slb/server/%s/port/' % self._server_name) 50 | self.assertEqual(params, expected) 51 | 52 | def test_create_port_with_params(self): 53 | expected = { 54 | 'port': { 55 | "conn-resume": 500, 56 | "conn-limit": 600, 57 | "stats-data-action": "stats-data-disable", 58 | "weight": 3, 59 | "port-number": 80, 60 | "range": 30, 61 | "action": "disable-with-health-check", 62 | "protocol": 'tcp' 63 | } 64 | } 65 | self.port.create('test_server', 80, 'tcp', conn_resume=500, conn_limit=600, 66 | stats_data_action="stats-data-disable", weight=3, range=30, 67 | action="disable-with-health-check") 68 | 69 | ((method, url, params, header), kwargs) = self.client.http.request.call_args 70 | 71 | self.assertEqual(method, 'POST') 72 | self.assertEqual(url, '/axapi/v3/slb/server/%s/port/' % self._server_name) 73 | self.assertEqual(params, expected) 74 | 75 | def test_update_port(self): 76 | expected = { 77 | 'port': { 78 | "conn-resume": 500, 79 | "conn-limit": 600, 80 | "stats-data-action": "stats-data-disable", 81 | "weight": 3, 82 | "port-number": 80, 83 | "range": 30, 84 | "action": "disable-with-health-check", 85 | "protocol": 'tcp' 86 | } 87 | } 88 | self.port.update('test_server', 80, 'tcp', conn_resume=500, conn_limit=600, 89 | stats_data_action="stats-data-disable", weight=3, range=30, 90 | action="disable-with-health-check") 91 | 92 | ((method, url, params, header), kwargs) = self.client.http.request.call_args 93 | 94 | self.assertEqual(method, 'PUT') 95 | self.assertEqual(url, '/axapi/v3/slb/server/%s/port/%s+%s/' % 96 | (self._server_name, 80, 'tcp')) 97 | self.assertEqual(params, expected) 98 | 99 | def test_delete_port(self): 100 | self.port.delete('test_server', 80, 'tcp') 101 | 102 | ((method, url, params, header), kwargs) = self.client.http.request.call_args 103 | 104 | self.assertEqual(method, 'DELETE') 105 | self.assertEqual(url, '/axapi/v3/slb/server/%s/port/%s+%s/' % 106 | (self._server_name, 80, 'tcp')) 107 | -------------------------------------------------------------------------------- /acos_client/v30/overlay/vtep.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client.v30 import base 18 | 19 | 20 | class OverlayVtep(base.BaseV30): 21 | url_prefix = "/overlay-tunnel/vtep" 22 | ip_url_format = "{baseurl}/{vtep}/{addrtype}" 23 | 24 | def get(self, vtep_id, *args, **kwargs): 25 | url = "{0}/{1}".format(self.url_prefix, vtep_id) 26 | return self._get(url, **kwargs) 27 | 28 | def get_list(self, *args, **kwargs): 29 | return self._get(self.url_prefix) 30 | 31 | def create(self, vtep_id, source_ip=None, source_vnis=[], 32 | dest_ips=[], lif_id=None, encap_type="vxlan", **kwargs): 33 | # vtep_id = ID 34 | # source_ip = source-ip-address 35 | # source_vnis = vni-list for source-ip-address 36 | # dest_ips = list of (ip, [vni_info]) tuples 37 | # vtep creation can be as simple or complicated as we like 38 | # we can create a vtep with a minimum of an ID 39 | # or we can create it with fully populated src/dst info 40 | 41 | is_found = False 42 | 43 | try: 44 | existing = self.get(vtep_id) 45 | is_found = existing is not None 46 | except Exception: 47 | pass 48 | 49 | if not is_found: 50 | # Create it. 51 | payload = { 52 | "vtep": { 53 | "id": vtep_id, 54 | } 55 | } 56 | existing = self._post(self.url_prefix, payload, **kwargs) 57 | # iterate later. 58 | dest_ip = dest_ips[0] 59 | vni = source_vnis[0] 60 | if source_ip: 61 | payload, url = self._build_ip_payload_and_url(vtep_id, "source", source_ip, encap_type, vni) 62 | self._post(url, payload) 63 | 64 | if dest_ip: 65 | payload, url = self._build_ip_payload_and_url(vtep_id, "destination", dest_ip, encap_type, vni) 66 | self._post(url, payload) 67 | 68 | return self.get(vtep_id) 69 | 70 | def update(self, vtep_id, ip_address, encap_type="vxlan", **kwargs): 71 | post_url = "{0}/{vtepid}/destination-ip-address/".format(self.url_prefix, vtepid=vtep_id) 72 | payload = { 73 | "destination-ip-address": { 74 | "ip-address": ip_address, 75 | } 76 | } 77 | return self._post(post_url, payload, **kwargs) 78 | 79 | def delete(self, vtep_id, **kwargs): 80 | post_url = "{0}/{vtepid}".format(self.url_prefix, vtepid=vtep_id) 81 | 82 | return self._delete(post_url) 83 | 84 | def _add_source_address(self, vtep_id, ip_address, vnis=[]): 85 | pass 86 | 87 | def _add_destination_address(self, vtep_id, ip_address, vnis=[]): 88 | pass 89 | 90 | def _add_source_vni(self, vtep_id, ip_address, segment, partition=None, gateway=None, lif=None): 91 | pass 92 | 93 | def _add_destination_vni(self, vtep_id, ip_address, segment): 94 | pass 95 | 96 | def _build_ip_payload_and_url(self, vtep_id, target, ip_address, encap_type, vni, lif_id=None): 97 | addr_type = "{0}-ip-address".format(target) 98 | 99 | payload = { 100 | addr_type: { 101 | "ip-address": ip_address, 102 | } 103 | } 104 | if lif_id and target == "source": 105 | payload[addr_type]["vni-list"] = [{"segment": vni, "partition": "shared", "lif": lif_id}] 106 | 107 | if target == "destination": 108 | payload[addr_type]["encap"] = encap_type 109 | 110 | url = self.ip_url_format.format(baseurl=self.url_prefix, vtep=vtep_id, addrtype=addr_type) 111 | 112 | return payload, url 113 | -------------------------------------------------------------------------------- /acos_client/v30/slb/server.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014, Jeff Buttars, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | from acos_client import errors as acos_errors 18 | from acos_client.v30 import base 19 | from acos_client.v30.slb.port import Port 20 | 21 | 22 | class Server(base.BaseV30): 23 | 24 | url_prefix = '/slb/server/' 25 | 26 | def get(self, name, max_retries=None, timeout=None, **kwargs): 27 | return self._get(self.url_prefix + name, max_retries=max_retries, timeout=timeout, 28 | axapi_args=kwargs) 29 | 30 | def exists(self, name): 31 | try: 32 | self.get(name) 33 | return True 34 | except acos_errors.NotFound: 35 | return False 36 | 37 | def get_all(self): 38 | return self._get(self.url_prefix) 39 | 40 | def _set(self, name, ip_address, status=1, server_templates=None, port_list=None, 41 | conn_resume=None, conn_limit=None, health_check=None, **kwargs): 42 | params = { 43 | "server": { 44 | "name": name, 45 | "action": 'enable' if status else 'disable', 46 | "conn-resume": conn_resume, 47 | "conn-limit": conn_limit, 48 | "health-check": health_check, 49 | } 50 | } 51 | 52 | if port_list: 53 | params['server']['port-list'] = port_list 54 | 55 | if self._is_ipv6(ip_address): 56 | params['server']['server-ipv6-addr'] = ip_address 57 | else: 58 | params['server']['host'] = ip_address 59 | 60 | if server_templates: 61 | server_templates = {k: v for k, v in server_templates.items() if v} 62 | params['server']['template-server'] = server_templates.get('template-server') 63 | 64 | return params 65 | 66 | def create(self, name, ip_address, status=1, server_templates=None, 67 | port_list=None, max_retries=None, timeout=None, 68 | conn_resume=None, conn_limit=None, health_check=None, **kwargs): 69 | params = self._set(name, ip_address, status=status, port_list=port_list, 70 | conn_resume=conn_resume, conn_limit=conn_limit, health_check=health_check, 71 | server_templates=server_templates, **kwargs) 72 | return self._post(self.url_prefix, params, max_retries=max_retries, timeout=timeout, 73 | axapi_args=kwargs) 74 | 75 | def update(self, name, ip_address, status=1, server_templates=None, 76 | port_list=None, max_retries=None, timeout=None, 77 | conn_resume=None, conn_limit=None, health_check=None, **kwargs): 78 | params = self._set(name, ip_address, status=status, port_list=port_list, 79 | conn_resume=conn_resume, conn_limit=conn_limit, health_check=health_check, 80 | server_templates=server_templates, **kwargs) 81 | return self._post(self.url_prefix + name, params, max_retries=max_retries, timeout=timeout, 82 | axapi_args=kwargs) 83 | 84 | def replace(self, name, ip_address, status=1, server_templates=None, 85 | port_list=None, max_retries=None, timeout=None, 86 | conn_resume=None, conn_limit=None, health_check=None, **kwargs): 87 | params = self._set(name, ip_address, status=status, port_list=port_list, 88 | conn_resume=conn_resume, conn_limit=conn_limit, health_check=health_check, 89 | server_templates=server_templates, **kwargs) 90 | return self._put(self.url_prefix + name, params, max_retries=max_retries, timeout=timeout, 91 | axapi_args=kwargs) 92 | 93 | def delete(self, name): 94 | return self._delete(self.url_prefix + name) 95 | 96 | @property 97 | def port(self): 98 | return Port(self.client) 99 | -------------------------------------------------------------------------------- /acos_client/tests/unit/v30/test_slb_aflex.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014-2016, Omkar Telee, A10 Networks. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | from __future__ import absolute_import 15 | from __future__ import unicode_literals 16 | 17 | try: 18 | import unittest 19 | from unittest import mock 20 | except ImportError: 21 | import mock 22 | import unittest2 as unittest 23 | 24 | from acos_client import client 25 | import acos_client.errors as acos_errors 26 | import responses 27 | 28 | 29 | HOSTNAME = 'fake_a10' 30 | BASE_URL = 'https://{}:443/axapi/v3'.format(HOSTNAME) 31 | AUTH_URL = '{}/auth'.format(BASE_URL) 32 | AFLEX_NAME = 'test1' 33 | CREATE_URL = '{}/file/aflex/'.format(BASE_URL) 34 | OBJECT_URL = '{}/file/aflex/{}'.format(BASE_URL, AFLEX_NAME) 35 | 36 | 37 | class TestAFlex(unittest.TestCase): 38 | 39 | def setUp(self): 40 | self.client = client.Client(HOSTNAME, '30', 'fake_username', 'fake_password') 41 | 42 | @mock.patch('acos_client.v30.slb.aflex_policy.AFlexPolicy.get') 43 | @responses.activate 44 | def test_aflex_create(self, mocked_get): 45 | mocked_get.side_effect = acos_errors.NotFound 46 | responses.add(responses.POST, AUTH_URL, json={'session_id': 'foobar'}) 47 | json_response = {"foo": "bar"} 48 | responses.add(responses.POST, CREATE_URL, json=json_response, status=200) 49 | filename = "testaflexpolicy" 50 | script = "when RULE_INIT{ change }" 51 | size = len(script.encode('utf-8')) 52 | action = "import" 53 | 54 | resp = self.client.slb.aflex_policy.create(filename, script, size, action) 55 | self.assertEqual(resp, json_response) 56 | self.assertEqual(len(responses.calls), 2) 57 | self.assertEqual(responses.calls[1].request.method, responses.POST) 58 | self.assertEqual(responses.calls[1].request.url, CREATE_URL) 59 | self.assertIn(filename, responses.calls[1].request.body.decode("utf-8")) 60 | self.assertIn(action, responses.calls[1].request.body.decode("utf-8")) 61 | 62 | @mock.patch('acos_client.v30.slb.aflex_policy.AFlexPolicy.get') 63 | @responses.activate 64 | def test_aflex_update(self, mocked_get): 65 | mocked_get.side_effect = acos_errors.NotFound 66 | responses.add(responses.POST, AUTH_URL, json={'session_id': 'foobar'}) 67 | json_response = {"foo": "bar"} 68 | responses.add(responses.POST, CREATE_URL, json=json_response, status=200) 69 | filename = "testaflexpolicy" 70 | script = "when RULE_INIT{}" 71 | size = len(script.encode('utf-8')) 72 | action = "import" 73 | 74 | resp = self.client.slb.aflex_policy.update(filename, script, size, action) 75 | self.assertEqual(resp, json_response) 76 | self.assertEqual(len(responses.calls), 2) 77 | self.assertEqual(responses.calls[1].request.method, responses.POST) 78 | self.assertEqual(responses.calls[1].request.url, CREATE_URL) 79 | self.assertIn(filename, responses.calls[1].request.body.decode("utf-8")) 80 | self.assertIn(action, responses.calls[1].request.body.decode("utf-8")) 81 | 82 | @mock.patch('acos_client.v30.slb.aflex_policy.AFlexPolicy.get') 83 | @responses.activate 84 | def test_aflex_delete(self, mocked_get): 85 | mocked_get.side_effect = acos_errors.NotFound 86 | responses.add(responses.POST, AUTH_URL, json={'session_id': 'foobar'}) 87 | json_response = {"foo": "bar"} 88 | responses.add(responses.POST, CREATE_URL, json=json_response, status=200) 89 | filename = "testaflexpolicy" 90 | 91 | resp = self.client.slb.aflex_policy.delete(filename) 92 | self.assertEqual(resp, json_response) 93 | self.assertEqual(len(responses.calls), 2) 94 | self.assertEqual(responses.calls[1].request.method, responses.POST) 95 | self.assertEqual(responses.calls[1].request.url, CREATE_URL) 96 | self.assertIn(filename, responses.calls[1].request.body.decode("utf-8")) 97 | self.assertIn('delete', responses.calls[1].request.body.decode("utf-8")) 98 | -------------------------------------------------------------------------------- /acos_client/v30/glm/license.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2021, A10 Networks Inc. All rights reserved. 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from acos_client import errors as acos_errors 16 | from acos_client.v30 import base 17 | 18 | 19 | class LicenseRequest(base.BaseV30): 20 | url_prefix = '/glm/create-license-request' 21 | 22 | def _set(self, create_license_request): 23 | params = { 24 | 'create-license-request': create_license_request 25 | } 26 | 27 | return params 28 | 29 | def create(self, create_license_request=None, **kwargs): 30 | params = self._set(create_license_request=None) 31 | return self._post(self.url_prefix, params, axapi_args=kwargs) 32 | 33 | def update(self, create_license_request=None, **kwargs): 34 | params = self._set(create_license_request=None) 35 | return self._post(self.url_prefix, params, axapi_args=kwargs) 36 | 37 | def put(self, create_license_request=None, **kwargs): 38 | params = self._set(create_license_request=None) 39 | return self._put(self.url_prefix, params, axapi_args=kwargs) 40 | 41 | def delete(self): 42 | return self._delete(self.url_prefix) 43 | 44 | 45 | class MultiLicenseException(Exception): 46 | 47 | def __init__(self): 48 | self.message = ("Only one of the following attributes can be " 49 | "used to define a new license: existing_org, " 50 | "existing_user, new_user, or name. These cannot " 51 | "be used in conjuction.") 52 | super(MultiLicenseException, self).__init__() 53 | 54 | 55 | class NewLicense(base.BaseV30): 56 | url_prefix = '/glm/new-license' 57 | 58 | def create(self, account_name=None, country=None, existing_org=None, 59 | glm_password=None, last_name=None, name=None, new_email=None, 60 | new_password=None, new_user=None, org_id=None, phone=None, 61 | license_type=None, existing_user=None, first_name=None, 62 | glm_email=None): 63 | params = { 64 | "new-license": {} 65 | } 66 | 67 | xor = bool(existing_org) + bool(existing_user) + bool(new_user) + bool(name) 68 | 69 | if xor > 1: 70 | raise MultiLicenseException() 71 | 72 | if existing_org: 73 | params['new-license'] = self.minimal_dict({ 74 | 'existing-org': existing_org, 75 | 'org-id': org_id 76 | }) 77 | elif existing_user: 78 | if not glm_email: 79 | raise acos_errors.RequiredAttributeNotSpecified( 80 | self.url_prefix, "existing_user", ["glm_email"]) 81 | 82 | params['new-license'] = self.minimal_dict({ 83 | 'existing-user': existing_user, 84 | 'glm-email': glm_email, 85 | 'glm-password': glm_password 86 | }) 87 | elif new_user: 88 | if not new_email: 89 | raise acos_errors.RequiredAttributeNotSpecified( 90 | self.url_prefix, "new_user", ["new_email"]) 91 | 92 | params['new-license'] = self.minimal_dict({ 93 | 'new-user': new_user, 94 | 'new-email': new_email, 95 | 'new-password': new_password, 96 | 'account-name': account_name, 97 | 'first-name': first_name, 98 | 'last-name': last_name, 99 | 'country': country, 100 | 'phone': phone 101 | }) 102 | elif name: 103 | if not license_type: 104 | raise acos_errors.RequiredAttributeNotSpecified( 105 | self.url_prefix, "name", ["license_type"]) 106 | 107 | params['new-license'] = self.minimal_dict({ 108 | 'name': name, 109 | 'type': license_type 110 | }) 111 | 112 | self._post(self.url_prefix, params) 113 | --------------------------------------------------------------------------------