python-designateclient-2.11.0/0000775000175000017500000000000013366600247016305 5ustar zuulzuul00000000000000python-designateclient-2.11.0/python-designateclient.sublime-project0000666000175000017500000000136213366577761026036 0ustar zuulzuul00000000000000{ "folders": [ { "file_exclude_patterns": [ "*.pyc", "*.pyo", "*.exe", "*.dll", "*.obj", "*.o", "*.a", "*.lib", "*.so", "*.dylib", "*.ncb", "*.sdf", "*.suo", "*.pdb", "*.idb", ".DS_Store", "*.class", "*.psd", "*.db", ".vagrant", ".noseids" ], "folder_exclude_patterns": [ ".svn", ".git", ".hg", "CVS", "*.egg", "*.egg-info", ".tox", "venv" ], "path": "." } ], "settings": { "default_line_ending": "unix", "detect_indentation": false, "ensure_newline_at_eof_on_save": true, "rulers": [ 79 ], "tab_size": 4, "translate_tabs_to_spaces": true, "trim_trailing_white_space_on_save": true } } python-designateclient-2.11.0/setup.cfg0000666000175000017500000001751213366600247020136 0ustar zuulzuul00000000000000[metadata] name = python-designateclient summary = OpenStack DNS-as-a-Service - Client description-file = README.rst license = Apache License, Version 2.0 author = OpenStack author-email = openstack-dev@lists.openstack.org home-page = https://docs.openstack.org/python-designateclient/latest classifier = Environment :: OpenStack Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.5 Topic :: Internet :: Name Service (DNS) [global] setup-hooks = pbr.hooks.setup_hook [files] packages = designateclient scripts = bin/designate [entry_points] designateclient.v1.controllers = reports = designateclient.v1.reports:ReportsController diagnostics = designateclient.v1.diagnostics:DiagnosticsController domains = designateclient.v1.domains:DomainsController records = designateclient.v1.records:RecordsController servers = designateclient.v1.servers:ServersController quotas = designateclient.v1.quotas:QuotasController sync = designateclient.v1.sync:SyncController touch = designateclient.v1.touch:TouchController designateclient.cli = domain-list = designateclient.cli.domains:ListDomainsCommand domain-get = designateclient.cli.domains:GetDomainCommand domain-create = designateclient.cli.domains:CreateDomainCommand domain-update = designateclient.cli.domains:UpdateDomainCommand domain-delete = designateclient.cli.domains:DeleteDomainCommand domain-servers-list = designateclient.cli.domains:ListDomainServersCommand record-list = designateclient.cli.records:ListRecordsCommand record-get = designateclient.cli.records:GetRecordCommand record-create = designateclient.cli.records:CreateRecordCommand record-update = designateclient.cli.records:UpdateRecordCommand record-delete = designateclient.cli.records:DeleteRecordCommand server-list = designateclient.cli.servers:ListServersCommand server-get = designateclient.cli.servers:GetServerCommand server-create = designateclient.cli.servers:CreateServerCommand server-update = designateclient.cli.servers:UpdateServerCommand server-delete = designateclient.cli.servers:DeleteServerCommand diagnostics-ping = designateclient.cli.diagnostics:PingCommand sync-all = designateclient.cli.sync:SyncAllCommand sync-domain = designateclient.cli.sync:SyncDomainCommand sync-record = designateclient.cli.sync:SyncRecordCommand touch-domain = designateclient.cli.touch:TouchDomainCommand report-count-all = designateclient.cli.reports:CountsCommand report-count-domains = designateclient.cli.reports:DomainCountCommand report-count-records = designateclient.cli.reports:RecordCountCommand report-count-tenants = designateclient.cli.reports:TenantCountCommand report-tenants-all = designateclient.cli.reports:TenantsCommand report-tenant-domains = designateclient.cli.reports:TenantCommand quota-get = designateclient.cli.quotas:GetQuotaCommand quota-update = designateclient.cli.quotas:UpdateQuotaCommand quota-reset = designateclient.cli.quotas:ResetQuotaCommand designateclient.versions = 1 = designateclient.v1:Client 2 = designateclient.v2.client:Client openstack.cli.extension = dns = designateclient.osc.plugin openstack.dns.v2 = zone_blacklist_create = designateclient.v2.cli.blacklists:CreateBlacklistCommand zone_blacklist_list = designateclient.v2.cli.blacklists:ListBlacklistsCommand zone_blacklist_show = designateclient.v2.cli.blacklists:ShowBlacklistCommand zone_blacklist_set = designateclient.v2.cli.blacklists:SetBlacklistCommand zone_blacklist_delete = designateclient.v2.cli.blacklists:DeleteBlacklistCommand tld_create = designateclient.v2.cli.tlds:CreateTLDCommand tld_list = designateclient.v2.cli.tlds:ListTLDsCommand tld_show = designateclient.v2.cli.tlds:ShowTLDCommand tld_set = designateclient.v2.cli.tlds:SetTLDCommand tld_delete = designateclient.v2.cli.tlds:DeleteTLDCommand zone_create = designateclient.v2.cli.zones:CreateZoneCommand zone_list = designateclient.v2.cli.zones:ListZonesCommand zone_show = designateclient.v2.cli.zones:ShowZoneCommand zone_set = designateclient.v2.cli.zones:SetZoneCommand zone_delete = designateclient.v2.cli.zones:DeleteZoneCommand zone_abandon = designateclient.v2.cli.zones:AbandonZoneCommand zone_axfr = designateclient.v2.cli.zones:AXFRZoneCommand zone_export_create = designateclient.v2.cli.zones:ExportZoneCommand zone_export_list = designateclient.v2.cli.zones:ListZoneExportsCommand zone_export_show = designateclient.v2.cli.zones:ShowZoneExportCommand zone_export_delete = designateclient.v2.cli.zones:DeleteZoneExportCommand zone_export_showfile = designateclient.v2.cli.zones:ShowZoneExportFileCommand zone_import_create = designateclient.v2.cli.zones:ImportZoneCommand zone_import_list = designateclient.v2.cli.zones:ListZoneImportsCommand zone_import_show = designateclient.v2.cli.zones:ShowZoneImportCommand zone_import_delete = designateclient.v2.cli.zones:DeleteZoneImportCommand zone_transfer_request_create = designateclient.v2.cli.zones:CreateTransferRequestCommand zone_transfer_request_list = designateclient.v2.cli.zones:ListTransferRequestsCommand zone_transfer_request_show = designateclient.v2.cli.zones:ShowTransferRequestCommand zone_transfer_request_set = designateclient.v2.cli.zones:SetTransferRequestCommand zone_transfer_request_delete = designateclient.v2.cli.zones:DeleteTransferRequestCommand zone_transfer_accept_request = designateclient.v2.cli.zones:AcceptTransferRequestCommand zone_transfer_accept_list = designateclient.v2.cli.zones:ListTransferAcceptsCommand zone_transfer_accept_show = designateclient.v2.cli.zones:ShowTransferAcceptCommand recordset_create = designateclient.v2.cli.recordsets:CreateRecordSetCommand recordset_list = designateclient.v2.cli.recordsets:ListRecordSetsCommand recordset_show = designateclient.v2.cli.recordsets:ShowRecordSetCommand recordset_set = designateclient.v2.cli.recordsets:SetRecordSetCommand recordset_delete = designateclient.v2.cli.recordsets:DeleteRecordSetCommand ptr_record_list = designateclient.v2.cli.reverse:ListFloatingIPCommand ptr_record_show = designateclient.v2.cli.reverse:ShowFloatingIPCommand ptr_record_set = designateclient.v2.cli.reverse:SetFloatingIPCommand ptr_record_unset = designateclient.v2.cli.reverse:UnsetFloatingIPCommand dns_service_list = designateclient.v2.cli.service_statuses:ListServiceStatusesCommand dns_service_show = designateclient.v2.cli.service_statuses:ShowServiceStatusCommand dns_quota_list = designateclient.v2.cli.quotas:ListQuotasCommand dns_quota_set = designateclient.v2.cli.quotas:SetQuotasCommand dns_quota_reset = designateclient.v2.cli.quotas:ResetQuotasCommand tsigkey_create = designateclient.v2.cli.tsigkeys:CreateTSIGKeyCommand tsigkey_list = designateclient.v2.cli.tsigkeys:ListTSIGKeysCommand tsigkey_show = designateclient.v2.cli.tsigkeys:ShowTSIGKeyCommand tsigkey_set = designateclient.v2.cli.tsigkeys:SetTSIGKeyCommand tsigkey_delete = designateclient.v2.cli.tsigkeys:DeleteTSIGKeyCommand [build_sphinx] builders = html,man all-files = 1 warning-is-error = 1 build-dir = doc/build source-dir = doc/source [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [compile_catalog] directory = designateclient/locale domain = designateclient [update_catalog] domain = designateclient output_dir = designateclient/locale input_file = designateclient/locale/designateclient.pot [extract_messages] keywords = _ gettext ngettext l_ lazy_gettext mapping_file = babel.cfg output_file = designateclient/locale/designateclient.pot [wheel] universal = 1 [pbr] autodoc_index_modules = True api_doc_dir = reference/api autodoc_exclude_modules = designateclient.tests.* designateclient.functionaltests.* python-designateclient-2.11.0/test-requirements.txt0000666000175000017500000000113313366577761022564 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. # Hacking already pins down pep8, pyflakes and flake8 hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0 mock>=2.0.0 # BSD oslo.config>=5.2.0 # Apache-2.0 oslotest>=3.2.0 # Apache-2.0 os-testr>=1.0.0 # Apache-2.0 python-subunit>=1.0.0 # Apache-2.0/BSD requests-mock>=1.2.0 # Apache-2.0 stestr>=2.0.0 # Apache-2.0 reno>=2.5.0 # Apache-2.0 tempest>=17.1.0 # Apache-2.0 python-designateclient-2.11.0/CONTRIBUTING.rst0000666000175000017500000000105413366577761020766 0ustar zuulzuul00000000000000If you would like to contribute to the development of OpenStack, you must follow the steps documented at: https://docs.openstack.org/infra/manual/developers.html Once those steps have been completed, changes to OpenStack should be submitted for review via the Gerrit tool, following the workflow documented at: https://docs.openstack.org/infra/manual/developers.html#development-workflow Pull requests submitted through GitHub will be ignored. Bugs should be filed on Launchpad, not GitHub: https://bugs.launchpad.net/python-designateclient python-designateclient-2.11.0/.zuul.yaml0000666000175000017500000000054113366577761020266 0ustar zuulzuul00000000000000- project: templates: - check-requirements - designate-devstack-jobs - openstack-cover-jobs - openstack-lower-constraints-jobs - openstack-python-jobs - openstack-python35-jobs - openstack-python36-jobs - openstackclient-plugin-jobs - publish-openstack-docs-pti gate: queue: designate python-designateclient-2.11.0/ChangeLog0000664000175000017500000004003613366600247020062 0ustar zuulzuul00000000000000CHANGES ======= 2.11.0 ------ * Don't quote {posargs} in tox.ini * Use templates for cover and lower-constraints * add python 3.6 unit test job * switch documentation job to new PTI * import zuul job settings from project-config * Update reno for stable/rocky 2.10.0 ------ * Switch to stestr * Fix copy-pasta in quota command descriptions * server-get/update show wrong values about 'id' and 'update\_at' * Remove PyPI downloads * fix tox python3 overrides * Trivial: Update pypi url to new url * Updated from global requirements * Check item is one of six.string\_types not just str * add lower-constraints job * Updated from global requirements * Updated from global requirements * Add os-testr in test-requirements.txt * Updated from global requirements * Updated from global requirements * Updated from global requirements * Highlight V1 API removal * Improve the RecordSet Update UI * Update reno for stable/queens 2.9.0 ----- * Updated from global requirements * Partial Revert "Remove unneeded requirements file" * Updated from global requirements 2.8.0 ----- * Updated from global requirements * Split doc requirements into their own file * Remove unneeded requirements file * Improve recordset create UI * Avoid tox\_install.sh for constraints support * Use jobs from designate repo * Remove setting of version/release from releasenotes * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * Make remote error handling more robust * Updated from global requirements * Update the documentation link for doc migration * Update reno for stable/pike * Updated from global requirements * Update and optimize documentation links 2.7.0 ----- * Updated from global requirements * switch from oslosphinx to openstackdocstheme * import cli-reference material from openstack-manuals * rearrange the existing docs into the new standard layout * use setuptools to build the docs even for testing * Update cli docs * Add tsig key support to python-designateclient * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * tox: Whitelist rm * doc: Remove cruft from conf.py * Use Sphinx 1.5 warning-is-error * Explicitly set 'builders' option * Updated from global requirements * [Fix gate]Update test requirement * Updated from global requirements * Simplify OSC doc structure * Updated from global requirements * Set client module \_\_version\_\_ * Update reno for stable/ocata 2.6.0 ----- * Add attribute support to create zone cli * Show proper error on over quota commands * Fix broken link for modindex 2.5.0 ----- * Updated from global requirements * Add Python 3.5 classifier and venv * Updated from global requirements * Remove 'coding: utf-8' from license statement * Removes unnecessary utf-8 encoding * Add Constraints support * Updated from global requirements 2.4.0 ----- * Ensure X-Designate-Edit-Managed-Records header value is a string * Updated from global requirements * Show team and repo badges on README * Use tempest instead of Tempest-lib * Replace 'assertFalse(a in b)' with 'assertNotIn(a, b)' * Updated from global requirements * Updated from global requirements * Ensure X-Auth-All-Projects header value is a string * Updated from global requirements * Add plug-in summary for osc doc * Updated from global requirements * Updated from global requirements * Fix for bug 1627945 * Enable release notes translation * Changed the author and author-email value * Replace 'assertTrue(a in b)' with 'assertIn(a, b)' * Updated from global requirements * Add oslo.config to test-requirements * Updated from global requirements * Fix pep8 E501 line too long * record-create/update: Account for priority being 0 * Update reno for stable/newton 2.3.0 ----- * Updated from global requirements * Resolve FloatingIP PTR records clis argument's description * Docs update for FloatingIP's ptr records * Fix clis related to FloatingIP's ptr records * Updated from global requirements * Remove discover from test-requirements * Updated from global requirements * Updated from global requirements 2.2.0 ----- * Updated from global requirements * Updated from global requirements * Use osc\_lib instead of cliff * Updated from global requirements * Add quota set / list / reset commands * Mark the v1 API Client as deprecated * Add global flags to cli * Updated from global requirements * Use osc-lib instead of openstackclient * Revert "Add Global Flags for filtering results" * Updated from global requirements * Add pool listing to python designate client * Add \`openstack zone transfer accept list\` cli to designateclient * Allow cli to query "v2/recordsets" * Updated from global requirements * Add Global Flags for filtering results * Updated from global requirements * Use the correct capitalization of OpenStack * Updated from global requirements * Update the home-page with developer documentation * Add reno support for release notes * Switch to keystoneauth * Added CONTRIBUTING.rst file * Docs Update * Updated from global requirements * Don't use the 'keystone' client (functional tests) * Update doc examples to use keystoneauth * Update designate cli page with more examples Closes-Bug: #1578207 * Add python-openstackclient to test-requirements * Improve python-designateclient docs * Updated from global requirements * Add support for service status * Fix a race condition in one of the zone import tests * Run the functional tests in a more verbose mode * Show responses on zone and recordset deletes * Implement zone import * Doc changes for installation webpage * Fix an issue causing a blacklist test to fail * Add filtering to recordsets CLI * Show "status" and "action" for recordsets * Move all V2 Controllers to inherit from the v2 * Fixes 'openstack tld list' command's exception * Implement zone export * Updated from global requirements * Improved TestRecordsetNegative * Add a service catalog override to the functional tests * Updated from global requirements * Stop using non-existent method of Mock * Log stacktraces of MultipleExceptions in functionaltests * Updated from global requirements * Updated from global requirements * Updated from global requirements * Python3: Add support for urlparse 2.0.0 ----- * Allow the OSC CLI Plugin to walk pages * Improvement in zone transfer request command description * Fixed grammar mistake in shell.rst * Updated from global requirements * Update typos * Show output on transfer accept * Change to ShowOne to display output upon update * Updated from global requirements * Updated from global requirements * Put py34 first in the env order of tox * Replace assertEqual(None, \*) with assertIsNone in tests * Add a missing whitespace * Deprecated tox -downloadcache option removed * Indicate py34 support * Removes MANIFEST.in as it is not needed explicitely by PBR * Pass environment variables of proxy to tox * Remove py26 support from designateclient * Updated from global requirements * Updated from global requirements * Improve logging in designateclient * Support OS\_INTERFACE and set V2 API as default * Pass OS\_ENDPOINT\_TYPE from shell to client * Updated from global requirements * Adds changes related to py3 compatibility * Clearing out .pyc file before a tox run * Fix support for --os-endpoint * Updates shell doc of v1 client * Fixes doc for v2 cli * Add functional tests for blacklists * Add functional tests for tlds * Adds different filter option for zone listing * Updated from global requirements * Resolve TLD's by name * improve readme contents * Removes --name argument from zone set command * Fixes error over quota update * Fixes order of argument in assertEqual * Fixes typos in zone transfer request show command description * Add functional tests for recordsets * Flesh out zone-related test cases * Fixes exception message for zone creation command * Fixes target-project-id argument in zone transfer command * Removes name argument from openstack recordset set command * Fixes openstack zone blacklist set command * Added test cases for v2 client * Adds test cases for servers in designateclient * Adds test cases for domain in designate v1 client * Makes error msg more helpful * Add period in help message * Layout some functional tests for the V2 CLI 1.5.0 ----- * Updated from global requirements * Add formatting of output data * Added appropriate error message for designate cli * Meaningful Exception for over-quota on domains * Added test cases for reports in designateclient * Added diagnostics,sync and touch test cases for v1 designateclient * V2 CLI Support * Added quotas and servers test cases for designateclient * Added test cases for designate v1 client * Make is so exceptions have some message * Updated from global requirements * Update github's URL * Updated from global requirements * Implement socket timeout in v1 * Don't wildcard resolve names * Updated from global requirements * Updated from global requirements * Improve help strings 1.4.0 ----- * Convert byte to str for py3 compatibilty * Updated from global requirements * Updated from global requirements * Add some missing Unit Tests to test\_utils.py * Solve some py3 compatibilty issues * Fix py3 compatibilty issues * Updated from global requirements * Replacing print with print() to provide py 2/3 compatibility * Updated from global requirements * Updated from global requirements * Fix for ttl values * Log error message from EndpointNotFound exceptions * Removed peronal email address from example 1.3.0 ----- * Updated from global requirements * Fix backwards compat for edit\_managed/all\_tenants * Add .eggs to gitignore * Add backwards compat for edit\_managed/all\_tenants * Updated from global requirements * Updated from global requirements * Updated from global requirements * Update github link * Sync tox.ini and add py34 * Use oslosphinx from PyPi * Drop incubating theme from docs * Move all\_tenants and edit\_managed attributes to designate Client * Log a more informative error upon EndpointNotFound * Updated from global requirements * V2 Bindings * Add --edit-managed flag to cli * Updated from global requirements * Allow relative names in record-create 1.2.0 ----- * Update README to work with release tools * Uncap library requirements for liberty * Allow to use domain names instead of ids * Updated from global requirements * Added extra previllege to list all domains from all tenants * Updated from global requirements * Updated from global requirements * Fix if checking on ttl for Create/Update commands * Updated from global requirements * Workflow documentation is now in infra-manual 1.1.1 ----- * Refactor KS session creation and support CA certs * Move some useful code outside v1 * Make token + endpoints work correctly * Move session creation up to shell * Set defaults for endpoint\_type and service\_type * Updated from global requirements * Use keystone sessions for v1 client * Fixes homepage in metadata and internal docs * Updated from global requirements * Updated from global requirements * Fixes pypi tarball not delivering Apache 2.0 LICENSE file * Updated from global requirements * Updated from global requirements 1.1.0 ----- * Add support for SOA records * sync and touch Commands Extend the base.DeleteCommand * Updated from global requirements * Updated from global requirements * Add support for quotas for v1 cli / bindings * Enable hacking check H104 * Added oslosphinx theme, and enabled the incubating option * Enabled hacking check H401 * Support Keystone V3 authentication * Support better logging (Fixes --debug option) * Update hacking package, fix/ignore new style errors * Updated from global requirements * Update .gitreview for repository move * Use six.add\_metaclass instead of \_\_metaclass\_\_ * Add dummy tests 1.0.3 ----- * designate record-list should display record data * Correct Python bindings create-record example * Standardize doc requirements 1.0.2 ----- * Ensure that url stripping is done correctly * Sync with global-requirements 1.0.1 ----- * Support versionless catalog URLs * Correctly support multiple regions * Update global requirements * Fix misspellings in python designateclient * Disable verbose logging by default * There are no mox tests, so remove dependency * Remove dependencies on pep8, pyflakes and flake8 * Sync with global requirements * Fix and enable gating on H306 * Support building wheels (PEP-427) * Add touch-domain to CLI * Move "sync" commands out of Diagnostics and fix them 1.0.0 ----- * Keyring is not actually used * Remove outdated version value from setup.cfg * Added domain and record description editing * Sync requirements with stable/havana requirements * Ensure TTL is treated as an int in the CLI 0.0.5 ----- * Update dependency versions * Ensure Invalid JSON and errors during deletes are displayed correctly * Correct two Record examples in the binding docs * Add Python bindings docs * first drop of python-designateclient docs * Ensure beta versions are not downloaded from pypi * Add a --insecure arg to ignore invalid SSL certs * Ensure we only list sphinx as a dep once * Use Python 3.x compatible except construct 0.0.4 ----- * Allow auth using a pre-fetched token * Update to PBR 0.5.21+ * doc/requirements.txt should be a proxy * Remove comments from \*requirements.txt (workaround pbr bug) * Sync with openstack/requirements * Rename to designate in .gitreview * Rename Moniker -> Designate * Add Hacking checks * Migrate to PBR * Always allow overriding the endpoint * Switch to flake8 and testr * Added reporting functionality to Moniker client * Correct diagnostics URI * Include type when listing records 0.0.3 ----- * Support loading resources from 3rd party packages. E.g. client extensions * Allow for controllers to be loaded dynamically * Add a command to list the nameservers for a domain * List commands should show a reduced set of columns * Add keyring to pip-requires * Clean error message display :) * Cleanup optional and obsolete CLI params * Rename OS\_SERVICE\_ENDPOINT env var to OS\_DNS\_ENDPOINT * Sync JSONSchemas * Rename OS\_SERVICE\_TYPE env var to OS\_DNS\_SERVICE\_TYPE 0.0.2 ----- * Sync JSONSchemas * Have tox.ini actually run nosetests * Pin to jsonschema less than 1.0 * Add support for administrative access (via X-Moniker-Sudo-Tenant-ID header) * Ensure resources and tools/\* are included in sdist * Add diagnostics to Python API and CLI 0.0.1 ----- * Bump JSONSchema version to 0.8, tracking the server component * Attempt to support both cliff 1.2 and 1.3 * Re-add version.py * Sync with Oslo 30a50c8a * Sync Schemas * Add support for supplying custom service type * Fixup MANIFEST.in * Ensure we supply Oslo Version with the correct \`python\_package\` name * Sync with oslo a8973c52 * Ensure \`moniker --version\` reports the correct version number * Sync with oslo-incubator ad93e4e3 0.0.1.alpha1 ------------ * Actually use the \*correct\* version of requests * Depend on and update for requests>1.0 (Matching {keystone,cinder,nova}client) * Depend on cliff>=1.2.1 * Support record priority in the CLI * Support CLI updating of domains/records/servers * Ensure Update Records and Servers works correctly in the Python API * Sync JSON-Schemas * Provide a sane error message when --os-auth-url or --os-endpoint have not been supplied * Handle HTTP 400 errors somewhat more sanely * Ensure Warlock passes the approperiate error message along with it's exceptions * Include setup-requires in tox.ini * Positionals don't need require=Bool * Sync with Oslo e6c576d9 * Remove unused code * Ensure Servers CLI args are defined correctly * Sync Server JSONSchema * Fixup pyflakes issue * Add Records and Servers CLI commands * Add ID as a positional argument to GetCommand * More helpers in the base Controller * Fix actual != expected row count for items * Initial Python client bindings and CLI * Initial Domain/Record/Server model skeletons * Sync tox.ini with moniker repo * Add PyFlakes tox env * Add JSONSchemas * Sync with OS-Common 3d6c2368 + Use OS-C's Version Module * Rename package to python-monikerclient * Add pypi trove classifiers * Cache pip downloads on Jenkins * Fixup tox.ini for Stackforge+Gerrit * Exit with the correct return code * Initial Commit - CLI Skeleton python-designateclient-2.11.0/.stestr.conf0000666000175000017500000000011113366577761020567 0ustar zuulzuul00000000000000[DEFAULT] test_path=${OS_TEST_PATH:-./designateclient/tests} top_dir=./ python-designateclient-2.11.0/python_designateclient.egg-info/0000775000175000017500000000000013366600247024542 5ustar zuulzuul00000000000000python-designateclient-2.11.0/python_designateclient.egg-info/pbr.json0000664000175000017500000000005613366600247026221 0ustar zuulzuul00000000000000{"git_version": "f0b7eb4", "is_release": true}python-designateclient-2.11.0/python_designateclient.egg-info/entry_points.txt0000664000175000017500000001424013366600247030041 0ustar zuulzuul00000000000000[designateclient.cli] diagnostics-ping = designateclient.cli.diagnostics:PingCommand domain-create = designateclient.cli.domains:CreateDomainCommand domain-delete = designateclient.cli.domains:DeleteDomainCommand domain-get = designateclient.cli.domains:GetDomainCommand domain-list = designateclient.cli.domains:ListDomainsCommand domain-servers-list = designateclient.cli.domains:ListDomainServersCommand domain-update = designateclient.cli.domains:UpdateDomainCommand quota-get = designateclient.cli.quotas:GetQuotaCommand quota-reset = designateclient.cli.quotas:ResetQuotaCommand quota-update = designateclient.cli.quotas:UpdateQuotaCommand record-create = designateclient.cli.records:CreateRecordCommand record-delete = designateclient.cli.records:DeleteRecordCommand record-get = designateclient.cli.records:GetRecordCommand record-list = designateclient.cli.records:ListRecordsCommand record-update = designateclient.cli.records:UpdateRecordCommand report-count-all = designateclient.cli.reports:CountsCommand report-count-domains = designateclient.cli.reports:DomainCountCommand report-count-records = designateclient.cli.reports:RecordCountCommand report-count-tenants = designateclient.cli.reports:TenantCountCommand report-tenant-domains = designateclient.cli.reports:TenantCommand report-tenants-all = designateclient.cli.reports:TenantsCommand server-create = designateclient.cli.servers:CreateServerCommand server-delete = designateclient.cli.servers:DeleteServerCommand server-get = designateclient.cli.servers:GetServerCommand server-list = designateclient.cli.servers:ListServersCommand server-update = designateclient.cli.servers:UpdateServerCommand sync-all = designateclient.cli.sync:SyncAllCommand sync-domain = designateclient.cli.sync:SyncDomainCommand sync-record = designateclient.cli.sync:SyncRecordCommand touch-domain = designateclient.cli.touch:TouchDomainCommand [designateclient.v1.controllers] diagnostics = designateclient.v1.diagnostics:DiagnosticsController domains = designateclient.v1.domains:DomainsController quotas = designateclient.v1.quotas:QuotasController records = designateclient.v1.records:RecordsController reports = designateclient.v1.reports:ReportsController servers = designateclient.v1.servers:ServersController sync = designateclient.v1.sync:SyncController touch = designateclient.v1.touch:TouchController [designateclient.versions] 1 = designateclient.v1:Client 2 = designateclient.v2.client:Client [openstack.cli.extension] dns = designateclient.osc.plugin [openstack.dns.v2] dns_quota_list = designateclient.v2.cli.quotas:ListQuotasCommand dns_quota_reset = designateclient.v2.cli.quotas:ResetQuotasCommand dns_quota_set = designateclient.v2.cli.quotas:SetQuotasCommand dns_service_list = designateclient.v2.cli.service_statuses:ListServiceStatusesCommand dns_service_show = designateclient.v2.cli.service_statuses:ShowServiceStatusCommand ptr_record_list = designateclient.v2.cli.reverse:ListFloatingIPCommand ptr_record_set = designateclient.v2.cli.reverse:SetFloatingIPCommand ptr_record_show = designateclient.v2.cli.reverse:ShowFloatingIPCommand ptr_record_unset = designateclient.v2.cli.reverse:UnsetFloatingIPCommand recordset_create = designateclient.v2.cli.recordsets:CreateRecordSetCommand recordset_delete = designateclient.v2.cli.recordsets:DeleteRecordSetCommand recordset_list = designateclient.v2.cli.recordsets:ListRecordSetsCommand recordset_set = designateclient.v2.cli.recordsets:SetRecordSetCommand recordset_show = designateclient.v2.cli.recordsets:ShowRecordSetCommand tld_create = designateclient.v2.cli.tlds:CreateTLDCommand tld_delete = designateclient.v2.cli.tlds:DeleteTLDCommand tld_list = designateclient.v2.cli.tlds:ListTLDsCommand tld_set = designateclient.v2.cli.tlds:SetTLDCommand tld_show = designateclient.v2.cli.tlds:ShowTLDCommand tsigkey_create = designateclient.v2.cli.tsigkeys:CreateTSIGKeyCommand tsigkey_delete = designateclient.v2.cli.tsigkeys:DeleteTSIGKeyCommand tsigkey_list = designateclient.v2.cli.tsigkeys:ListTSIGKeysCommand tsigkey_set = designateclient.v2.cli.tsigkeys:SetTSIGKeyCommand tsigkey_show = designateclient.v2.cli.tsigkeys:ShowTSIGKeyCommand zone_abandon = designateclient.v2.cli.zones:AbandonZoneCommand zone_axfr = designateclient.v2.cli.zones:AXFRZoneCommand zone_blacklist_create = designateclient.v2.cli.blacklists:CreateBlacklistCommand zone_blacklist_delete = designateclient.v2.cli.blacklists:DeleteBlacklistCommand zone_blacklist_list = designateclient.v2.cli.blacklists:ListBlacklistsCommand zone_blacklist_set = designateclient.v2.cli.blacklists:SetBlacklistCommand zone_blacklist_show = designateclient.v2.cli.blacklists:ShowBlacklistCommand zone_create = designateclient.v2.cli.zones:CreateZoneCommand zone_delete = designateclient.v2.cli.zones:DeleteZoneCommand zone_export_create = designateclient.v2.cli.zones:ExportZoneCommand zone_export_delete = designateclient.v2.cli.zones:DeleteZoneExportCommand zone_export_list = designateclient.v2.cli.zones:ListZoneExportsCommand zone_export_show = designateclient.v2.cli.zones:ShowZoneExportCommand zone_export_showfile = designateclient.v2.cli.zones:ShowZoneExportFileCommand zone_import_create = designateclient.v2.cli.zones:ImportZoneCommand zone_import_delete = designateclient.v2.cli.zones:DeleteZoneImportCommand zone_import_list = designateclient.v2.cli.zones:ListZoneImportsCommand zone_import_show = designateclient.v2.cli.zones:ShowZoneImportCommand zone_list = designateclient.v2.cli.zones:ListZonesCommand zone_set = designateclient.v2.cli.zones:SetZoneCommand zone_show = designateclient.v2.cli.zones:ShowZoneCommand zone_transfer_accept_list = designateclient.v2.cli.zones:ListTransferAcceptsCommand zone_transfer_accept_request = designateclient.v2.cli.zones:AcceptTransferRequestCommand zone_transfer_accept_show = designateclient.v2.cli.zones:ShowTransferAcceptCommand zone_transfer_request_create = designateclient.v2.cli.zones:CreateTransferRequestCommand zone_transfer_request_delete = designateclient.v2.cli.zones:DeleteTransferRequestCommand zone_transfer_request_list = designateclient.v2.cli.zones:ListTransferRequestsCommand zone_transfer_request_set = designateclient.v2.cli.zones:SetTransferRequestCommand zone_transfer_request_show = designateclient.v2.cli.zones:ShowTransferRequestCommand python-designateclient-2.11.0/python_designateclient.egg-info/not-zip-safe0000664000175000017500000000000113366600247026770 0ustar zuulzuul00000000000000 python-designateclient-2.11.0/python_designateclient.egg-info/dependency_links.txt0000664000175000017500000000000113366600247030610 0ustar zuulzuul00000000000000 python-designateclient-2.11.0/python_designateclient.egg-info/PKG-INFO0000664000175000017500000000523613366600247025645 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-designateclient Version: 2.11.0 Summary: OpenStack DNS-as-a-Service - Client Home-page: https://docs.openstack.org/python-designateclient/latest Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/python-designateclient.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on Python bindings to the Designate API ===================================== .. image:: https://img.shields.io/pypi/v/python-designateclient.svg :target: https://pypi.org/project/python-designateclient/ :alt: Latest Version This is a client library for Designate built on the Designate API. It provides a Python API (the ``designateclient`` module) and a command-line tool (``designate``). Development takes place via the usual OpenStack processes as outlined in the `developer guide `_. The master repository is in `Git `_. See release notes and more at ``_. * License: Apache License, Version 2.0 * `PyPi`_ - package installation * `Online Documentation`_ * `Bugs`_ - issue tracking * `Source`_ * `How to Contribute`_ .. _PyPi: https://pypi.org/project/python-designateclient .. _Online Documentation: https://docs.openstack.org/python-designateclient/latest/ .. _Bugs: https://bugs.launchpad.net/python-designateclient .. _Source: https://git.openstack.org/cgit/openstack/python-designateclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Internet :: Name Service (DNS) python-designateclient-2.11.0/python_designateclient.egg-info/requires.txt0000664000175000017500000000027413366600247027145 0ustar zuulzuul00000000000000cliff!=2.9.0,>=2.8.0 jsonschema<3.0.0,>=2.6.0 osc-lib>=1.8.0 oslo.utils>=3.33.0 pbr!=2.1.0,>=2.0.0 keystoneauth1>=3.4.0 requests>=2.14.2 six>=1.10.0 stevedore>=1.20.0 debtcollector>=1.2.0 python-designateclient-2.11.0/python_designateclient.egg-info/top_level.txt0000664000175000017500000000002013366600247027264 0ustar zuulzuul00000000000000designateclient python-designateclient-2.11.0/python_designateclient.egg-info/SOURCES.txt0000664000175000017500000001226713366600247026436 0ustar zuulzuul00000000000000.stestr.conf .zuul.yaml AUTHORS CONTRIBUTING.rst ChangeLog LICENSE README.rst lower-constraints.txt python-designateclient.sublime-project requirements.txt setup.cfg setup.py test-requirements.txt tox.ini bin/designate designateclient/__init__.py designateclient/client.py designateclient/exceptions.py designateclient/shell.py designateclient/utils.py designateclient/version.py designateclient/warlock.py designateclient/cli/__init__.py designateclient/cli/base.py designateclient/cli/diagnostics.py designateclient/cli/domains.py designateclient/cli/quotas.py designateclient/cli/records.py designateclient/cli/reports.py designateclient/cli/servers.py designateclient/cli/sync.py designateclient/cli/touch.py designateclient/functionaltests/__init__.py designateclient/functionaltests/base.py designateclient/functionaltests/client.py designateclient/functionaltests/config.py designateclient/functionaltests/datagen.py designateclient/functionaltests/models.py designateclient/functionaltests/v2/__init__.py designateclient/functionaltests/v2/fixtures.py designateclient/functionaltests/v2/test_blacklist.py designateclient/functionaltests/v2/test_recordsets.py designateclient/functionaltests/v2/test_tlds.py designateclient/functionaltests/v2/test_tsigkeys.py designateclient/functionaltests/v2/test_zone.py designateclient/functionaltests/v2/test_zone_export.py designateclient/functionaltests/v2/test_zone_import.py designateclient/functionaltests/v2/test_zone_transfer.py designateclient/osc/__init__.py designateclient/osc/plugin.py designateclient/resources/schemas/v1/domain.json designateclient/resources/schemas/v1/record.json designateclient/resources/schemas/v1/server.json designateclient/tests/__init__.py designateclient/tests/base.py designateclient/tests/test_designateclient.py designateclient/tests/test_exceptions.py designateclient/tests/test_utils.py designateclient/tests/test_v1/__init__.py designateclient/tests/test_v1/test_client.py designateclient/tests/test_v1/test_diagnostics.py designateclient/tests/test_v1/test_domain.py designateclient/tests/test_v1/test_quotas.py designateclient/tests/test_v1/test_records.py designateclient/tests/test_v1/test_reports.py designateclient/tests/test_v1/test_servers.py designateclient/tests/test_v1/test_sync.py designateclient/tests/test_v1/test_touch.py designateclient/tests/v2/__init__.py designateclient/tests/v2/test_blacklists.py designateclient/tests/v2/test_client.py designateclient/tests/v2/test_limits.py designateclient/tests/v2/test_nameservers.py designateclient/tests/v2/test_recordsets.py designateclient/tests/v2/test_reverse.py designateclient/tests/v2/test_service_statuses.py designateclient/tests/v2/test_timeout.py designateclient/tests/v2/test_tlds.py designateclient/tests/v2/test_tsigkeys.py designateclient/tests/v2/test_zones.py designateclient/v1/__init__.py designateclient/v1/diagnostics.py designateclient/v1/domains.py designateclient/v1/quotas.py designateclient/v1/records.py designateclient/v1/reports.py designateclient/v1/servers.py designateclient/v1/sync.py designateclient/v1/touch.py designateclient/v2/__init__.py designateclient/v2/base.py designateclient/v2/blacklists.py designateclient/v2/client.py designateclient/v2/limits.py designateclient/v2/nameservers.py designateclient/v2/pools.py designateclient/v2/quotas.py designateclient/v2/recordsets.py designateclient/v2/reverse.py designateclient/v2/service_statuses.py designateclient/v2/tlds.py designateclient/v2/tsigkeys.py designateclient/v2/utils.py designateclient/v2/zones.py designateclient/v2/cli/__init__.py designateclient/v2/cli/blacklists.py designateclient/v2/cli/common.py designateclient/v2/cli/quotas.py designateclient/v2/cli/recordsets.py designateclient/v2/cli/reverse.py designateclient/v2/cli/service_statuses.py designateclient/v2/cli/tlds.py designateclient/v2/cli/tsigkeys.py designateclient/v2/cli/zones.py doc/requirements.txt doc/examples/recordset_create.py doc/examples/recordset_crud.py doc/examples/zone_create_primary.py doc/examples/zone_create_secondary.py doc/examples/zone_list_nameservers.py doc/examples/zone_list_paging.py doc/source/conf.py doc/source/index.rst doc/source/cli/index.rst doc/source/contributor/contributing.rst doc/source/contributor/functional-tests.rst doc/source/contributor/index.rst doc/source/install/index.rst doc/source/reference/index.rst doc/source/user/bindings.rst doc/source/user/index.rst doc/source/user/shell-examples.rst doc/source/user/shell-v2.rst doc/source/user/shell.rst python_designateclient.egg-info/PKG-INFO python_designateclient.egg-info/SOURCES.txt python_designateclient.egg-info/dependency_links.txt python_designateclient.egg-info/entry_points.txt python_designateclient.egg-info/not-zip-safe python_designateclient.egg-info/pbr.json python_designateclient.egg-info/requires.txt python_designateclient.egg-info/top_level.txt releasenotes/notes/.placeholder releasenotes/notes/quota-commands-7ff037bddae95771.yaml releasenotes/source/conf.py releasenotes/source/index.rst releasenotes/source/newton.rst releasenotes/source/ocata.rst releasenotes/source/pike.rst releasenotes/source/queens.rst releasenotes/source/rocky.rst releasenotes/source/unreleased.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholderpython-designateclient-2.11.0/releasenotes/0000775000175000017500000000000013366600247020776 5ustar zuulzuul00000000000000python-designateclient-2.11.0/releasenotes/source/0000775000175000017500000000000013366600247022276 5ustar zuulzuul00000000000000python-designateclient-2.11.0/releasenotes/source/_templates/0000775000175000017500000000000013366600247024433 5ustar zuulzuul00000000000000python-designateclient-2.11.0/releasenotes/source/_templates/.placeholder0000666000175000017500000000000013366577761026724 0ustar zuulzuul00000000000000python-designateclient-2.11.0/releasenotes/source/index.rst0000666000175000017500000000027513366577761024163 0ustar zuulzuul00000000000000================================ Designate Client Release Notes ================================ .. toctree:: :maxdepth: 1 unreleased rocky queens pike ocata newton python-designateclient-2.11.0/releasenotes/source/ocata.rst0000666000175000017500000000023013366577761024132 0ustar zuulzuul00000000000000=================================== Ocata Series Release Notes =================================== .. release-notes:: :branch: origin/stable/ocata python-designateclient-2.11.0/releasenotes/source/rocky.rst0000666000175000017500000000022113366577761024172 0ustar zuulzuul00000000000000=================================== Rocky Series Release Notes =================================== .. release-notes:: :branch: stable/rocky python-designateclient-2.11.0/releasenotes/source/unreleased.rst0000666000175000017500000000015713366577761025202 0ustar zuulzuul00000000000000============================== Current Series Release Notes ============================== .. release-notes::python-designateclient-2.11.0/releasenotes/source/newton.rst0000666000175000017500000000023213366577761024357 0ustar zuulzuul00000000000000=================================== Newton Series Release Notes =================================== .. release-notes:: :branch: origin/stable/newton python-designateclient-2.11.0/releasenotes/source/conf.py0000666000175000017500000002176313366577761023626 0ustar zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # Designate Release Notes documentation build configuration file, created by # sphinx-quickstart on Tue Nov 3 17:40:50 2015. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'openstackdocstheme', 'reno.sphinxext', ] # openstackdocstheme options repository_name = 'openstack/python-designateclient' bug_project = 'python-designateclient' bug_tag = '' html_last_updated_fmt = '%Y-%m-%d %H:%M' html_theme = 'openstackdocs' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Designate Client Release Notes' copyright = u'2015, Designate Developers' # Release notes are version independent. # The full version, including alpha/beta/rc tags. release = '' # The short X.Y version. version = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'DesignateClientReleaseNotesdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'DesignateClientReleaseNotes.tex', u'Designate Client Release Notes ' u'Documentation', u'Designate Developers', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'designateclientreleasenotes', u'Designate Client Release Notes ' u'Documentation', [u'Designate Developers'], 1) ] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'DesignateClientReleaseNotes', u'Designate Client Release Notes ' u'Documentation', u'Designate Developers', 'DesignateClientReleaseNotes', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] python-designateclient-2.11.0/releasenotes/source/pike.rst0000666000175000017500000000021713366577761024000 0ustar zuulzuul00000000000000=================================== Pike Series Release Notes =================================== .. release-notes:: :branch: stable/pike python-designateclient-2.11.0/releasenotes/source/_static/0000775000175000017500000000000013366600247023724 5ustar zuulzuul00000000000000python-designateclient-2.11.0/releasenotes/source/_static/.placeholder0000666000175000017500000000000013366577761026215 0ustar zuulzuul00000000000000python-designateclient-2.11.0/releasenotes/source/queens.rst0000666000175000017500000000022313366577761024345 0ustar zuulzuul00000000000000=================================== Queens Series Release Notes =================================== .. release-notes:: :branch: stable/queens python-designateclient-2.11.0/releasenotes/notes/0000775000175000017500000000000013366600247022126 5ustar zuulzuul00000000000000python-designateclient-2.11.0/releasenotes/notes/.placeholder0000666000175000017500000000000013366577761024417 0ustar zuulzuul00000000000000python-designateclient-2.11.0/releasenotes/notes/quota-commands-7ff037bddae95771.yaml0000666000175000017500000000040513366577761030270 0ustar zuulzuul00000000000000--- features: - added openstack dns quota command + list + set + reset sub commands All sub commands can be scoped to a project using --project-id If the --project-id does not match the current project id it will set X-Auth-All-Projects:True python-designateclient-2.11.0/tox.ini0000666000175000017500000000472413366577761017647 0ustar zuulzuul00000000000000[tox] envlist = py35,py27,flake8 minversion = 2.0 skipsdist = True [testenv] usedevelop = True install_command = pip install {opts} {packages} setenv = VIRTUAL_ENV={envdir} LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=C deps = -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt whitelist_externals = find sh rm commands = find . -type f -name "*.pyc" -delete stestr run --slowest {posargs} passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY [testenv:docs] basepython = python3 deps = -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} -r{toxinidir}/requirements.txt -r{toxinidir}/doc/requirements.txt commands = sphinx-build -b html doc/source doc/build/html [testenv:flake8] basepython = python3 commands = flake8 [testenv:pep8] basepython = python3 commands = flake8 [testenv:pyflakes] basepython = python3 commands = flake8 [testenv:cover] basepython = python3 setenv = PYTHON=coverage run --source designateclient --parallel-mode commands = stestr run {posargs} coverage combine coverage html -d cover coverage xml -o cover/coverage.xml [testenv:venv] basepython = python3 commands = {posargs} [testenv:functional] usedevelop = False setenv = {[testenv]setenv} OS_TEST_PATH=designateclient/functionaltests/ passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_LOG_CAPTURE OS_DEBUG TEMPEST_CONFIG [testenv:releasenotes] basepython = python3 commands = sphinx-build -a -E -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html [flake8] # ignored flake8 codes: # H302 import only modules # H402 one line docstring needs punctuation # H404 multi line docstring should start with a summary # H405 multi line docstring summary not separated with an empty line # H904 Wrap long lines in parentheses instead of a backslash # See designate for other ignored codes that may apply here ignore = H105, H302,H402,H404,H405,H904 builtins = _ exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,tools [testenv:lower-constraints] basepython = python3 deps = -c{toxinidir}/lower-constraints.txt -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt python-designateclient-2.11.0/designateclient/0000775000175000017500000000000013366600247021447 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/functionaltests/0000775000175000017500000000000013366600247024674 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/functionaltests/datagen.py0000666000175000017500000000337513366577761026701 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import random import string def random_digits(n=8): return "".join([random.choice(string.digits) for _ in range(n)]) def random_tld(name='testtld'): return "{0}{1}".format(name, random_digits()) def random_tsigkey_name(name='testtsig'): return "{0}{1}".format(name, random_digits()) def random_tsigkey_secret(name='test-secret'): return "{0}-{1}".format(name, random_digits(254 - len(name))) def random_zone_name(name='testdomain', tld='com'): return "{0}{1}.{2}.".format(name, random_digits(), tld) def random_a_recordset_name(zone_name, recordset_name='testrecord'): return "{0}{1}.{2}".format(recordset_name, random_digits(), zone_name) def random_blacklist(name='testblacklist'): return '{0}{1}'.format(name, random_digits()) def random_zone_file(name='testzoneimport'): return "$ORIGIN {0}{1}.com.\n" \ "$TTL 300\n" \ "{0}{1}.com. 300 IN SOA ns.{0}{1}.com. " \ "nsadmin.{0}{1}.com. 42 42 42 42 42\n" \ "{0}{1}.com. 300 IN NS ns.{0}{1}.com.\n" \ "{0}{1}.com. 300 IN MX 10 mail.{0}{1}.com.\n" \ "ns.{0}{1}.com. 300 IN A 10.0.0.1\n" \ "mail.{0}{1}.com. 300 IN A 10.0.0.2\n".format(name, random_digits()) python-designateclient-2.11.0/designateclient/functionaltests/__init__.py0000666000175000017500000000016713366577761027031 0ustar zuulzuul00000000000000import logging logging.basicConfig( filename='functional-tests.log', filemode='w', level=logging.DEBUG, ) python-designateclient-2.11.0/designateclient/functionaltests/models.py0000666000175000017500000000642413366577761026557 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import six from tempest.lib.cli import output_parser class Model(object): def __str__(self): return str(self.__dict__) class FieldValueModel(Model): """This converts cli output from messy lists/dicts to neat attributes.""" def __init__(self, out): """This parses output with fields and values like: +----------------+------------------------------+ | Field | Value | +----------------+------------------------------+ | action | CREATE | | created_at | 2015-08-20T17:22:17.000000 | | description | None | +----------------+------------------------------+ These are then accessible as: model.action model.created_at model.description """ table = output_parser.table(out) # Because the output_parser handles Values with multiple lines # in additional Field/Value pairs with Field name '', the following # code is necessary to aggregate Values. # # The list of Field/Value pairs is in-order, so we can append Value # continuation to the previously seen Field, with a newline separator. value_lines = [] prev_field = None for field, value in table['values']: if field == '': value_lines.append(value) setattr(self, prev_field, '\n'.join(value_lines)) else: setattr(self, field, value) prev_field = field value_lines = [value] class ListEntryModel(Model): def __init__(self, fields, values): for k, v in six.moves.zip(fields, values): setattr(self, k, v) class ListModel(Model, list): def __init__(self, out): """This parses an output table with any number of headers, and any number of entries: +--------------------------------------+----------+---------+ | id | name | type | +--------------------------------------+----------+---------+ | e658a875-1024-4f88-a347-e5b244ec5a10 | aaa.com. | PRIMARY | +--------------------------------------+----------+---------+ | 98d1fb5f-2954-448e-988e-6f1df0f24c52 | bbb.com. | PRIMARY | +--------------------------------------+----------+---------+ These are then accessible as: model[0].name == 'aaa.com.' model[1].name == 'bbb.com.' """ table = output_parser.table(out) for entry in table['values']: self.append(ListEntryModel(table['headers'], entry)) python-designateclient-2.11.0/designateclient/functionaltests/base.py0000666000175000017500000000301713366577761026201 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest.lib.cli import base from tempest.lib.exceptions import CommandFailed from designateclient.functionaltests import client from designateclient.functionaltests import config class BaseDesignateTest(base.ClientTestBase): def _get_clients(self): config.read_config() return client.DesignateCLI.as_user('default') def ensure_tld_exists(self, tld): try: self.clients.as_user('admin').tld_create(tld) except CommandFailed: pass def _is_entity_in_list(self, entity, entity_list): """Determines if the given entity exists in the given list. Uses the id for comparison. Certain entities (e.g. zone import, export) cannot be made comparable in a list of CLI output results, because the fields in a list command can be different from those in a show command. """ return any([entity_record.id == entity.id for entity_record in entity_list]) python-designateclient-2.11.0/designateclient/functionaltests/config.py0000666000175000017500000000405713366577761026541 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import os from oslo_config import cfg cfg.CONF.register_group(cfg.OptGroup( name='identity', title="Configuration for Keystone auth" )) cfg.CONF.register_group(cfg.OptGroup( name='designateclient', title="Configuration for the Designate client" )) cfg.CONF.register_opts([ cfg.StrOpt('uri', help="The Keystone v2 endpoint"), cfg.StrOpt('uri_v3', help="The Keystone v3 endpoint"), cfg.StrOpt('auth_version', default='v2'), cfg.StrOpt('region', default='RegionOne'), cfg.StrOpt('username'), cfg.StrOpt('tenant_name'), cfg.StrOpt('password', secret=True), cfg.StrOpt('domain_name'), cfg.StrOpt('alt_username'), cfg.StrOpt('alt_tenant_name'), cfg.StrOpt('alt_password', secret=True), cfg.StrOpt('alt_domain_name'), cfg.StrOpt('admin_username'), cfg.StrOpt('admin_tenant_name'), cfg.StrOpt('admin_password', secret=True), cfg.StrOpt('admin_domain_name'), cfg.StrOpt("override_endpoint", help="use this url instead of the url in the service catalog"), cfg.StrOpt("override_token", help="with the override endpoint, pass this token to the api"), ], group='identity') cfg.CONF.register_opts([ cfg.StrOpt('directory', help='the directory containing the client executable'), ], group='designateclient') def find_config_file(): return os.environ.get( 'TEMPEST_CONFIG', '/opt/stack/tempest/etc/tempest.conf') def read_config(): cfg.CONF(args=[], default_config_files=[find_config_file()]) python-designateclient-2.11.0/designateclient/functionaltests/client.py0000666000175000017500000003712213366577761026551 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import logging import os from tempest.lib.cli import base from designateclient.functionaltests.config import cfg from designateclient.functionaltests.models import FieldValueModel from designateclient.functionaltests.models import ListModel LOG = logging.getLogger(__name__) def build_option_string(options): """Format a string of option flags (--key 'value'). This will quote the values, in case spaces are included. Any values that are None are excluded entirely. Usage:: build_option_string({ "--email": "me@example.com", "--name": "example.com." "--ttl": None, }) Returns:: "--email 'me@example.com' --name 'example.com.' """ return " ".join("{0} '{1}'".format(flag, value) for flag, value in options.items() if value is not None) def build_flags_string(flags): """Format a string of value-less flags. Pass in a dictionary mapping flags to booleans. Those flags set to true are included in the returned string. Usage:: build_flags_string({ '--no-ttl': True, '--no-name': False, '--verbose': True, }) Returns:: '--no-ttl --verbose' """ flags = {flag: is_set for flag, is_set in flags.items() if is_set} return " ".join(flags.keys()) class ZoneCommands(object): """This is a mixin that provides zone commands to DesignateCLI""" def zone_list(self, *args, **kwargs): return self.parsed_cmd('zone list', ListModel, *args, **kwargs) def zone_show(self, id, *args, **kwargs): return self.parsed_cmd('zone show %s' % id, FieldValueModel, *args, **kwargs) def zone_delete(self, id, *args, **kwargs): return self.parsed_cmd('zone delete %s' % id, FieldValueModel, *args, **kwargs) def zone_create(self, name, email=None, ttl=None, description=None, type=None, masters=None, *args, **kwargs): options_str = build_option_string({ "--email": email, "--ttl": ttl, "--description": description, "--masters": masters, "--type": type, }) cmd = 'zone create {0} {1}'.format(name, options_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_set(self, id, email=None, ttl=None, description=None, type=None, masters=None, *args, **kwargs): options_str = build_option_string({ "--email": email, "--ttl": ttl, "--description": description, "--masters": masters, "--type": type, }) cmd = 'zone set {0} {1}'.format(id, options_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) class ZoneTransferCommands(object): """A mixin for DesignateCLI to add zone transfer commands""" def zone_transfer_request_list(self, *args, **kwargs): cmd = 'zone transfer request list' return self.parsed_cmd(cmd, ListModel, *args, **kwargs) def zone_transfer_request_create(self, zone_id, target_project_id=None, description=None, *args, **kwargs): options_str = build_option_string({ "--target-project-id": target_project_id, "--description": description, }) cmd = 'zone transfer request create {0} {1}'.format( zone_id, options_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_transfer_request_show(self, id, *args, **kwargs): cmd = 'zone transfer request show {0}'.format(id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_transfer_request_set(self, id, description=None, *args, **kwargs): options_str = build_option_string({"--description": description}) cmd = 'zone transfer request set {0} {1}'.format(options_str, id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_transfer_request_delete(self, id, *args, **kwargs): cmd = 'zone transfer request delete {0}'.format(id) return self.parsed_cmd(cmd, *args, **kwargs) def zone_transfer_accept_request(self, id, key, *args, **kwargs): options_str = build_option_string({ "--transfer-id": id, "--key": key, }) cmd = 'zone transfer accept request {0}'.format(options_str) return self.parsed_cmd(cmd, *args, **kwargs) def zone_transfer_accept_show(self, id, *args, **kwargs): cmd = 'zone transfer accept show {0}'.format(id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) class ZoneExportCommands(object): """A mixin for DesignateCLI to add zone export commands""" def zone_export_list(self, *args, **kwargs): cmd = 'zone export list' return self.parsed_cmd(cmd, ListModel, *args, **kwargs) def zone_export_create(self, zone_id, *args, **kwargs): cmd = 'zone export create {0}'.format( zone_id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_export_show(self, zone_export_id, *args, **kwargs): cmd = 'zone export show {0}'.format(zone_export_id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_export_delete(self, zone_export_id, *args, **kwargs): cmd = 'zone export delete {0}'.format(zone_export_id) return self.parsed_cmd(cmd, *args, **kwargs) def zone_export_showfile(self, zone_export_id, *args, **kwargs): cmd = 'zone export showfile {0}'.format(zone_export_id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) class ZoneImportCommands(object): """A mixin for DesignateCLI to add zone import commands""" def zone_import_list(self, *args, **kwargs): cmd = 'zone import list' return self.parsed_cmd(cmd, ListModel, *args, **kwargs) def zone_import_create(self, zone_file_path, *args, **kwargs): cmd = 'zone import create {0}'.format(zone_file_path) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_import_show(self, zone_import_id, *args, **kwargs): cmd = 'zone import show {0}'.format(zone_import_id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_import_delete(self, zone_import_id, *args, **kwargs): cmd = 'zone import delete {0}'.format(zone_import_id) return self.parsed_cmd(cmd, *args, **kwargs) class RecordsetCommands(object): def recordset_show(self, zone_id, id, *args, **kwargs): cmd = 'recordset show {0} {1}'.format(zone_id, id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def recordset_list(self, zone_id, *args, **kwargs): cmd = 'recordset list {0}'.format(zone_id) return self.parsed_cmd(cmd, ListModel, *args, **kwargs) def recordset_create(self, zone_id, name, records=None, type=None, description=None, ttl=None, *args, **kwargs): options_str = build_option_string({ '--records': records, '--type': type, '--description': description, '--ttl': ttl, }) cmd = 'recordset create {0} {1} {2}'.format(zone_id, name, options_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def recordset_set(self, zone_id, id, records=None, type=None, description=None, ttl=None, no_description=False, no_ttl=False, *args, **kwargs): options_str = build_option_string({ '--records': records, '--type': type, '--description': description, '--ttl': ttl, }) flags_str = build_flags_string({ '--no-description': no_description, '--no-ttl': no_ttl, }) cmd = 'recordset set {0} {1} {2} {3}'.format( zone_id, id, flags_str, options_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def recordset_delete(self, zone_id, id, *args, **kwargs): cmd = 'recordset delete {0} {1}'.format(zone_id, id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) class TLDCommands(object): def tld_list(self, *args, **kwargs): return self.parsed_cmd('tld list', ListModel, *args, **kwargs) def tld_show(self, id, *args, **kwargs): return self.parsed_cmd('tld show {0}'.format(id), FieldValueModel, *args, **kwargs) def tld_delete(self, id, *args, **kwargs): return self.parsed_cmd('tld delete {0}'.format(id), *args, **kwargs) def tld_create(self, name, description=None, *args, **kwargs): options_str = build_option_string({ '--name': name, '--description': description, }) cmd = 'tld create {0}'.format(options_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def tld_set(self, id, name=None, description=None, no_description=False, *args, **kwargs): options_str = build_option_string({ '--name': name, '--description': description, }) flags_str = build_flags_string({'--no-description': no_description}) cmd = 'tld set {0} {1} {2}'.format(id, options_str, flags_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) class TSIGKeyCommands(object): def tsigkey_list(self, *args, **kwargs): return self.parsed_cmd('tsigkey list', ListModel, *args, **kwargs) def tsigkey_show(self, id, *args, **kwargs): return self.parsed_cmd('tsigkey show {0}'.format(id), FieldValueModel, *args, **kwargs) def tsigkey_delete(self, id, *args, **kwargs): return self.parsed_cmd('tsigkey delete {0}'.format(id), *args, **kwargs) def tsigkey_create(self, name, algorithm, secret, scope, resource_id, *args, **kwargs): options_str = build_option_string({ '--name': name, '--algorithm': algorithm, '--secret': secret, '--scope': scope, '--resource-id': resource_id, }) cmd = 'tsigkey create {0}'.format(options_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def tsigkey_set(self, id, name=None, algorithm=None, secret=None, scope=None, *args, **kwargs): options_str = build_option_string({ '--name': name, '--algorithm': algorithm, '--secret': secret, '--scope': scope, }) cmd = 'tsigkey set {0} {1}'.format(id, options_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) class BlacklistCommands(object): def zone_blacklist_list(self, *args, **kwargs): cmd = 'zone blacklist list' return self.parsed_cmd(cmd, ListModel, *args, **kwargs) def zone_blacklist_create(self, pattern, description=None, *args, **kwargs): options_str = build_option_string({ '--pattern': pattern, '--description': description, }) cmd = 'zone blacklist create {0}'.format(options_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_blacklist_set(self, id, pattern=None, description=None, no_description=False, *args, **kwargs): options_str = build_option_string({ '--pattern': pattern, '--description': description, }) flags_str = build_flags_string({'--no-description': no_description}) cmd = 'zone blacklist set {0} {1} {2}'.format(id, options_str, flags_str) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_blacklist_show(self, id, *args, **kwargs): cmd = 'zone blacklist show {0}'.format(id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) def zone_blacklist_delete(self, id, *args, **kwargs): cmd = 'zone blacklist delete {0}'.format(id) return self.parsed_cmd(cmd, FieldValueModel, *args, **kwargs) class DesignateCLI(base.CLIClient, ZoneCommands, ZoneTransferCommands, ZoneExportCommands, ZoneImportCommands, RecordsetCommands, TLDCommands, BlacklistCommands): # instantiate this once to minimize requests to keystone _CLIENTS = None def __init__(self, *args, **kwargs): super(DesignateCLI, self).__init__(*args, **kwargs) # grab the project id. this is used for zone transfer requests resp = FieldValueModel(self.openstack('token issue')) self.project_id = resp.project_id @property def using_auth_override(self): return bool(cfg.CONF.identity.override_endpoint) @classmethod def get_clients(cls): if not cls._CLIENTS: cls._init_clients() return cls._CLIENTS @classmethod def _init_clients(cls): cls._CLIENTS = { 'default': DesignateCLI( cli_dir=cfg.CONF.designateclient.directory, username=cfg.CONF.identity.username, password=cfg.CONF.identity.password, tenant_name=cfg.CONF.identity.tenant_name, uri=cfg.CONF.identity.uri, ), 'alt': DesignateCLI( cli_dir=cfg.CONF.designateclient.directory, username=cfg.CONF.identity.alt_username, password=cfg.CONF.identity.alt_password, tenant_name=cfg.CONF.identity.alt_tenant_name, uri=cfg.CONF.identity.uri, ), 'admin': DesignateCLI( cli_dir=cfg.CONF.designateclient.directory, username=cfg.CONF.identity.admin_username, password=cfg.CONF.identity.admin_password, tenant_name=cfg.CONF.identity.admin_tenant_name, uri=cfg.CONF.identity.uri, ) } @classmethod def as_user(self, user): clients = self.get_clients() if user in clients: return clients[user] raise Exception("User '{0}' does not exist".format(user)) def parsed_cmd(self, cmd, model=None, *args, **kwargs): if self.using_auth_override: # use --os-url and --os-token func = self._openstack_noauth else: # use --os-username --os-tenant-name --os-password --os-auth-url func = self.openstack out = func(cmd, *args, **kwargs) LOG.debug(out) if model is not None: return model(out) return out def _openstack_noauth(self, cmd, *args, **kwargs): exe = os.path.join(cfg.CONF.designateclient.directory, 'openstack') options = build_option_string({ '--os-url': cfg.CONF.identity.override_endpoint, '--os-token': cfg.CONF.identity.override_token, }) cmd = options + " " + cmd return base.execute(exe, cmd, *args, **kwargs) python-designateclient-2.11.0/designateclient/functionaltests/v2/0000775000175000017500000000000013366600247025223 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/functionaltests/v2/test_tlds.py0000666000175000017500000000607513366577761027632 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest.lib.exceptions import CommandFailed from designateclient.functionaltests.base import BaseDesignateTest from designateclient.functionaltests.datagen import random_tld from designateclient.functionaltests.v2.fixtures import TLDFixture class TestTld(BaseDesignateTest): def setUp(self): super(TestTld, self).setUp() tld_name = random_tld() self.tld = self.useFixture(TLDFixture( name=tld_name, description='A random tld', )).tld self.assertEqual(self.tld.name, tld_name) self.assertEqual(self.tld.description, 'A random tld') def test_tld_list(self): tlds = self.clients.as_user('admin').tld_list() self.assertGreater(len(tlds), 0) def test_tld_create_and_show(self): tld = self.clients.as_user('admin').tld_show(self.tld.id) self.assertEqual(tld.name, self.tld.name) self.assertEqual(tld.created_at, self.tld.created_at) self.assertEqual(tld.id, self.tld.id) self.assertEqual(tld.name, self.tld.name) self.assertEqual(tld.updated_at, self.tld.updated_at) def test_tld_delete(self): client = self.clients.as_user('admin') client.tld_delete(self.tld.id) self.assertRaises(CommandFailed, client.tld_show, self.tld.id) def test_tld_set(self): client = self.clients.as_user('admin') updated_name = random_tld('updated') tld = client.tld_set(self.tld.id, name=updated_name, description='An updated tld') self.assertEqual(tld.description, 'An updated tld') self.assertEqual(tld.name, updated_name) def test_tld_set_no_description(self): client = self.clients.as_user('admin') tld = client.tld_set(self.tld.id, no_description=True) self.assertEqual(tld.description, 'None') def test_no_set_tld_with_description_and_no_description(self): client = self.clients.as_user('admin') self.assertRaises(CommandFailed, client.tld_set, self.tld.id, description='An updated tld', no_description=True) class TestTldNegative(BaseDesignateTest): def test_tld_invalid_commmand(self): client = self.clients.as_user('admin') self.assertRaises(CommandFailed, client.openstack, 'tld notacommand') def test_tld_create_invalid_flag(self): client = self.clients.as_user('admin') self.assertRaises(CommandFailed, client.openstack, 'tld create --notanoption "junk"') python-designateclient-2.11.0/designateclient/functionaltests/v2/__init__.py0000666000175000017500000000000013366577761027342 0ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/functionaltests/v2/fixtures.py0000666000175000017500000001757713366577761027507 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from __future__ import absolute_import from __future__ import print_function import sys import tempfile import traceback import fixtures from tempest.lib.exceptions import CommandFailed from testtools.runtest import MultipleExceptions from designateclient.functionaltests.client import DesignateCLI class BaseFixture(fixtures.Fixture): def __init__(self, user='default', *args, **kwargs): """args/kwargs are forwarded to a create method on DesignateCLI""" super(BaseFixture, self).__init__() self.args = args self.kwargs = kwargs self.client = DesignateCLI.as_user(user) def setUp(self): # Sometimes, exceptions are raised in _setUp methods on fixtures. # testtools pushes the exception into a MultipleExceptions object along # with an artificial SetupError, which produces bad error messages. # This just logs those stack traces to stderr for easier debugging. try: super(BaseFixture, self).setUp() except MultipleExceptions as e: for i, exc_info in enumerate(e.args): print('--- printing MultipleExceptions traceback {} of {} ---' .format(i + 1, len(e.args)), file=sys.stderr) traceback.print_exception(*exc_info) raise class ZoneFixture(BaseFixture): """See DesignateCLI.zone_create for __init__ args""" def _setUp(self): super(ZoneFixture, self)._setUp() self.zone = self.client.zone_create(*self.args, **self.kwargs) self.addCleanup(self.cleanup_zone, self.client, self.zone.id) @classmethod def cleanup_zone(cls, client, zone_id): try: client.zone_delete(zone_id) except CommandFailed: pass class TransferRequestFixture(BaseFixture): """See DesignateCLI.zone_transfer_request_create for __init__ args""" def __init__(self, zone, user='default', target_user='alt', *args, **kwargs): super(TransferRequestFixture, self).__init__(user, *args, **kwargs) self.zone = zone self.target_client = DesignateCLI.as_user(target_user) # the client has a bug such that it requires --target-project-id. # when this bug is fixed, please remove this self.kwargs['target_project_id'] = self.target_client.project_id def _setUp(self): super(TransferRequestFixture, self)._setUp() self.transfer_request = self.client.zone_transfer_request_create( zone_id=self.zone.id, *self.args, **self.kwargs ) self.addCleanup(self.cleanup_transfer_request, self.client, self.transfer_request.id) self.addCleanup(ZoneFixture.cleanup_zone, self.client, self.zone.id) self.addCleanup(ZoneFixture.cleanup_zone, self.target_client, self.zone.id) @classmethod def cleanup_transfer_request(cls, client, transfer_request_id): try: client.zone_transfer_request_delete(transfer_request_id) except CommandFailed: pass class ExportFixture(BaseFixture): """See DesignateCLI.zone_export_create for __init__ args""" def __init__(self, zone, user='default', *args, **kwargs): super(ExportFixture, self).__init__(user, *args, **kwargs) self.zone = zone def _setUp(self): super(ExportFixture, self)._setUp() self.zone_export = self.client.zone_export_create( zone_id=self.zone.id, *self.args, **self.kwargs ) self.addCleanup(self.cleanup_zone_export, self.client, self.zone_export.id) self.addCleanup(ZoneFixture.cleanup_zone, self.client, self.zone.id) @classmethod def cleanup_zone_export(cls, client, zone_export_id): try: client.zone_export_delete(zone_export_id) except CommandFailed: pass class ImportFixture(BaseFixture): """See DesignateCLI.zone_import_create for __init__ args""" def __init__(self, zone_file_contents, user='default', *args, **kwargs): super(ImportFixture, self).__init__(user, *args, **kwargs) self.zone_file_contents = zone_file_contents def _setUp(self): super(ImportFixture, self)._setUp() with tempfile.NamedTemporaryFile() as f: f.write(self.zone_file_contents) f.flush() self.zone_import = self.client.zone_import_create( zone_file_path=f.name, *self.args, **self.kwargs ) self.addCleanup(self.cleanup_zone_import, self.client, self.zone_import.id) self.addCleanup(ZoneFixture.cleanup_zone, self.client, self.zone_import.zone_id) @classmethod def cleanup_zone_import(cls, client, zone_import_id): try: client.zone_import_delete(zone_import_id) except CommandFailed: pass class RecordsetFixture(BaseFixture): """See DesignateCLI.recordset_create for __init__ args""" def _setUp(self): super(RecordsetFixture, self)._setUp() self.recordset = self.client.recordset_create( *self.args, **self.kwargs) self.addCleanup(self.cleanup_recordset, self.client, self.recordset.zone_id, self.recordset.id) @classmethod def cleanup_recordset(cls, client, zone_id, recordset_id): try: client.recordset_delete(zone_id, recordset_id) except CommandFailed: pass class TLDFixture(BaseFixture): """See DesignateCLI.tld_create for __init__ args""" def __init__(self, user='admin', *args, **kwargs): super(TLDFixture, self).__init__(user=user, *args, **kwargs) def _setUp(self): super(TLDFixture, self)._setUp() self.tld = self.client.tld_create(*self.args, **self.kwargs) self.addCleanup(self.cleanup_tld, self.client, self.tld.id) @classmethod def cleanup_tld(cls, client, tld_id): try: client.tld_delete(tld_id) except CommandFailed: pass class TSIGKeyFixture(BaseFixture): """See DesignateCLI.tsigkey_create for __init__ args""" def __init__(self, user='admin', *args, **kwargs): super(TSIGKeyFixture, self).__init__(user=user, *args, **kwargs) def _setUp(self): super(TSIGKeyFixture, self)._setUp() self.tsigkey = self.client.tsigkey_create(*self.args, **self.kwargs) self.addCleanup(self.cleanup_tsigkey(self.client, self.tsigkey.id)) @classmethod def cleanup_tsigkey(cls, client, tsigkey_id): try: client.tsigkey_delete(tsigkey_id) except CommandFailed: pass class BlacklistFixture(BaseFixture): """See DesignateCLI.zone_blacklist_create for __init__ args""" def __init__(self, user='admin', *args, **kwargs): super(BlacklistFixture, self).__init__(user=user, *args, **kwargs) def _setUp(self): super(BlacklistFixture, self)._setUp() self.blacklist = self.client.zone_blacklist_create(*self.args, **self.kwargs) self.addCleanup(self.cleanup_blacklist, self.client, self.blacklist.id) @classmethod def cleanup_blacklist(cls, client, blacklist_id): try: client.zone_blacklist_delete(blacklist_id) except CommandFailed: pass python-designateclient-2.11.0/designateclient/functionaltests/v2/test_zone.py0000666000175000017500000001157313366577761027636 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest.lib.exceptions import CommandFailed from designateclient.functionaltests.base import BaseDesignateTest from designateclient.functionaltests.datagen import random_zone_name from designateclient.functionaltests.v2.fixtures import ZoneFixture class TestZone(BaseDesignateTest): def setUp(self): super(TestZone, self).setUp() self.ensure_tld_exists('com') self.fixture = self.useFixture(ZoneFixture( name=random_zone_name(), email='test@example.com', )) self.zone = self.fixture.zone def test_zone_list(self): zones = self.clients.zone_list() self.assertGreater(len(zones), 0) def test_zone_create_and_show(self): zone = self.clients.zone_show(self.zone.id) self.assertTrue(hasattr(zone, 'action')) self.assertEqual(self.zone.created_at, zone.created_at) self.assertEqual(self.zone.description, zone.description) self.assertEqual(self.zone.email, zone.email) self.assertEqual(self.zone.id, zone.id) self.assertEqual(self.zone.masters, zone.masters) self.assertEqual(self.zone.name, zone.name) self.assertEqual(self.zone.pool_id, zone.pool_id) self.assertEqual(self.zone.project_id, zone.project_id) self.assertEqual(self.zone.serial, zone.serial) self.assertTrue(hasattr(zone, 'status')) self.assertEqual(self.zone.transferred_at, zone.transferred_at) self.assertEqual(self.zone.ttl, zone.ttl) self.assertEqual(self.zone.type, zone.type) self.assertEqual(self.zone.updated_at, zone.updated_at) self.assertEqual(self.zone.version, zone.version) def test_zone_delete(self): zone = self.clients.zone_delete(self.zone.id) self.assertEqual(zone.action, 'DELETE') self.assertEqual(zone.status, 'PENDING') def test_zone_set(self): ttl = int(self.zone.ttl) + 123 email = 'updated{0}'.format(self.zone.email) description = 'new description' zone = self.clients.zone_set(self.zone.id, ttl=ttl, email=email, description=description) self.assertEqual(ttl, int(zone.ttl)) self.assertEqual(email, zone.email) self.assertEqual(description, zone.description) def test_invalid_option_on_zone_create(self): cmd = 'zone create %s --invalid "not a valid option"'.format( random_zone_name()) self.assertRaises(CommandFailed, self.clients.openstack, cmd) def test_invalid_zone_command(self): cmd = 'zone hopefullynotacommand' self.assertRaises(CommandFailed, self.clients.openstack, cmd) class TestsPassingZoneFlags(BaseDesignateTest): def setUp(self): super(TestsPassingZoneFlags, self).setUp() self.ensure_tld_exists('com') def test_zone_create_primary_with_all_args(self): zone_name = random_zone_name() fixture = self.useFixture(ZoneFixture( name=zone_name, email='primary@example.com', description='A primary zone', ttl=2345, type='PRIMARY', )) zone = fixture.zone self.assertEqual(zone_name, zone.name) self.assertEqual('primary@example.com', zone.email) self.assertEqual('A primary zone', zone.description) self.assertEqual('2345', zone.ttl) self.assertEqual('PRIMARY', zone.type) def test_zone_create_secondary_with_all_args(self): zone_name = random_zone_name() fixture = self.useFixture(ZoneFixture( name=zone_name, description='A secondary zone', type='SECONDARY', masters='127.0.0.1', )) zone = fixture.zone self.assertEqual(zone_name, zone.name) self.assertEqual('A secondary zone', zone.description) self.assertEqual('SECONDARY', zone.type) self.assertEqual('127.0.0.1', zone.masters) def test_zone_set_secondary_masters(self): fixture = self.useFixture(ZoneFixture( name=random_zone_name(), description='A secondary zone', type='SECONDARY', masters='127.0.0.1', )) zone = fixture.zone self.assertEqual('127.0.0.1', zone.masters) zone = self.clients.zone_set(zone.id, masters='127.0.0.2') self.assertEqual('127.0.0.2', zone.masters) python-designateclient-2.11.0/designateclient/functionaltests/v2/test_tsigkeys.py0000666000175000017500000000736013366577761030524 0ustar zuulzuul00000000000000""" Copyright 2017 SAP SE Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest.lib.exceptions import CommandFailed from designateclient.functionaltests.base import BaseDesignateTest from designateclient.functionaltests.datagen import random_tsigkey_name from designateclient.functionaltests.datagen import random_tsigkey_secret from designateclient.functionaltests.datagen import random_zone_name from designateclient.functionaltests.v2.fixtures import TSIGKeyFixture from designateclient.functionaltests.v2.fixtures import ZoneFixture class TestTSIGKey(BaseDesignateTest): def setUp(self): super(TestTSIGKey, self).setUp() self.ensure_tsigkey_exists('com') self.zone = self.useFixture(ZoneFixture( name=random_zone_name(), email='test@example.com', )).zone tsig_name = random_tsigkey_name() tsig_algorithm = "hmac-sha256" tsig_secret = random_tsigkey_secret() tsig_scope = 'ZONE' self.tsig = self.useFixture(TSIGKeyFixture( name=tsig_name, algorithm=tsig_algorithm, secret=tsig_secret, scope=tsig_scope, resource_id=self.zone.id )).tsig self.assertEqual(self.tsig.name, tsig_name) self.assertEqual(self.tsig.algorithm, tsig_algorithm) self.assertEqual(self.tsig.secret, tsig_secret) self.assertEqual(self.tsig.scope, tsig_scope) self.assertEqual(self.tsig.resource_id, self.zone.id) def test_tsigkey_list(self): tsigkeys = self.clients.as_user('admin').tsigkey_list() self.assertGreater(len(tsigkeys), 0) def test_tsigkey_create_and_show(self): tsigkey = self.clients.as_user('admin').tsigkey_show(self.tsigkey.id) self.assertEqual(tsigkey.name, self.tsigkey.name) self.assertEqual(tsigkey.created_at, self.tsigkey.created_at) self.assertEqual(tsigkey.id, self.tsigkey.id) self.assertEqual(self.tsig.algorithm, self.tsig_algorithm) self.assertEqual(self.tsig.secret, self.tsig_secret) self.assertEqual(self.tsig.scope, self.tsig_scope) self.assertEqual(self.tsig.resource_id, self.zone.id) self.assertEqual(tsigkey.updated_at, self.tsigkey.updated_at) def test_tsigkey_delete(self): client = self.clients.as_user('admin') client.tsigkey_delete(self.tsigkey.id) self.assertRaises(CommandFailed, client.tsigkey_show, self.tsigkey.id) def test_tsigkey_set(self): client = self.clients.as_user('admin') updated_name = random_tsigkey_name('updated') tsigkey = client.tsigkey_set(self.tsigkey.id, name=updated_name, secret='An updated tsigsecret') self.assertEqual(tsigkey.secret, 'An updated tsigsecret') self.assertEqual(tsigkey.name, updated_name) class TestTSIGKeyNegative(BaseDesignateTest): def test_tsigkey_invalid_commmand(self): client = self.clients.as_user('admin') self.assertRaises(CommandFailed, client.openstack, 'tsigkey notacommand') def test_tsigkey_create_invalid_flag(self): client = self.clients.as_user('admin') self.assertRaises(CommandFailed, client.openstack, 'tsigkey create --notanoption "junk"') python-designateclient-2.11.0/designateclient/functionaltests/v2/test_zone_export.py0000666000175000017500000000573413366577761031241 0ustar zuulzuul00000000000000""" Copyright 2016 Rackspace Author: Rahman Syed Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from designateclient.functionaltests.base import BaseDesignateTest from designateclient.functionaltests.datagen import random_zone_name from designateclient.functionaltests.v2.fixtures import ExportFixture from designateclient.functionaltests.v2.fixtures import ZoneFixture class TestZoneExport(BaseDesignateTest): def setUp(self): super(TestZoneExport, self).setUp() self.ensure_tld_exists('com') fixture = self.useFixture(ZoneFixture( name=random_zone_name(), email='test@example.com', )) self.zone = fixture.zone def test_list_zone_exports(self): zone_export = self.useFixture(ExportFixture( zone=self.zone )).zone_export zone_exports = self.clients.zone_export_list() self.assertGreater(len(zone_exports), 0) self.assertTrue(self._is_entity_in_list(zone_export, zone_exports)) def test_create_and_show_zone_export(self): zone_export = self.useFixture(ExportFixture( zone=self.zone )).zone_export fetched_export = self.clients.zone_export_show(zone_export.id) self.assertEqual(zone_export.created_at, fetched_export.created_at) self.assertEqual(zone_export.id, fetched_export.id) self.assertEqual(zone_export.message, fetched_export.message) self.assertEqual(zone_export.project_id, fetched_export.project_id) self.assertEqual(zone_export.zone_id, fetched_export.zone_id) def test_delete_zone_export(self): zone_export = self.useFixture(ExportFixture( zone=self.zone )).zone_export zone_exports = self.clients.zone_export_list() self.assertTrue(self._is_entity_in_list(zone_export, zone_exports)) self.clients.zone_export_delete(zone_export.id) zone_exports = self.clients.zone_export_list() self.assertFalse(self._is_entity_in_list(zone_export, zone_exports)) def test_show_export_file(self): zone_export = self.useFixture(ExportFixture( zone=self.zone )).zone_export fetched_export = self.clients.zone_export_showfile(zone_export.id) self.assertIn('$ORIGIN', fetched_export.data) self.assertIn('$TTL', fetched_export.data) self.assertIn('SOA', fetched_export.data) self.assertIn('NS', fetched_export.data) self.assertIn(self.zone.name, fetched_export.data) python-designateclient-2.11.0/designateclient/functionaltests/v2/test_zone_transfer.py0000666000175000017500000001101713366577761031533 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import unittest from tempest.lib.exceptions import CommandFailed from designateclient.functionaltests.base import BaseDesignateTest from designateclient.functionaltests.client import DesignateCLI from designateclient.functionaltests.datagen import random_zone_name from designateclient.functionaltests.v2.fixtures import TransferRequestFixture from designateclient.functionaltests.v2.fixtures import ZoneFixture class TestZoneTransferRequest(BaseDesignateTest): def setUp(self): super(TestZoneTransferRequest, self).setUp() self.ensure_tld_exists('com') fixture = self.useFixture(ZoneFixture( name=random_zone_name(), email='test@example.com', )) self.zone = fixture.zone def test_list_zone_transfer_request(self): self.useFixture(TransferRequestFixture(self.zone)) xfrs = self.clients.zone_transfer_request_list() self.assertGreater(len(xfrs), 0) def test_create_and_show_zone_transfer_request(self): transfer_request = self.useFixture(TransferRequestFixture( zone=self.zone, user='default', target_user='alt', )).transfer_request fetched_xfr = self.clients.zone_transfer_request_show( transfer_request.id) self.assertEqual(fetched_xfr.created_at, transfer_request.created_at) self.assertEqual(fetched_xfr.description, transfer_request.description) self.assertEqual(fetched_xfr.id, transfer_request.id) self.assertEqual(fetched_xfr.key, transfer_request.key) self.assertEqual(fetched_xfr.links, transfer_request.links) self.assertEqual(fetched_xfr.target_project_id, transfer_request.target_project_id) self.assertEqual(fetched_xfr.updated_at, transfer_request.updated_at) self.assertEqual(fetched_xfr.status, transfer_request.status) self.assertEqual(fetched_xfr.zone_id, self.zone.id) self.assertEqual(fetched_xfr.zone_name, self.zone.name) def test_delete_zone_transfer_request(self): transfer_request = self.useFixture(TransferRequestFixture( zone=self.zone, user='default', target_user='alt', )).transfer_request self.clients.zone_transfer_request_delete(transfer_request.id) self.assertRaises(CommandFailed, self.clients.zone_transfer_request_show, transfer_request.id) @unittest.skip("Fails because `zone transfer request set` returns nothing") def test_set_zone_transfer_request(self): transfer_request = self.useFixture(TransferRequestFixture( zone=self.zone, description="old description", )).transfer_request self.assertEqual(transfer_request.description, "old description") updated_xfr = self.clients.zone_transfer_request_set( transfer_request.id, description="updated description") self.assertEqual(updated_xfr.description, "updated description") class TestZoneTransferAccept(BaseDesignateTest): def setUp(self): super(TestZoneTransferAccept, self).setUp() self.ensure_tld_exists('com') fixture = self.useFixture(ZoneFixture( name=random_zone_name(), email='test@example.com', )) self.zone = fixture.zone self.target_client = DesignateCLI.as_user('alt') fixture = self.useFixture(TransferRequestFixture( zone=self.zone, user='default', target_user='alt', target_project_id=self.target_client.project_id, )) self.transfer_request = fixture.transfer_request def test_zone_transfer_accept_request(self): self.target_client.zone_transfer_accept_request( id=self.transfer_request.id, key=self.transfer_request.key, ) self.target_client.zone_show(self.zone.id) self.assertRaises(CommandFailed, self.clients.zone_show, self.zone.id) python-designateclient-2.11.0/designateclient/functionaltests/v2/test_recordsets.py0000666000175000017500000001036313366577761031034 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest.lib.exceptions import CommandFailed from designateclient.functionaltests.base import BaseDesignateTest from designateclient.functionaltests.datagen import random_a_recordset_name from designateclient.functionaltests.datagen import random_zone_name from designateclient.functionaltests.v2.fixtures import RecordsetFixture from designateclient.functionaltests.v2.fixtures import ZoneFixture class TestRecordset(BaseDesignateTest): def setUp(self): super(TestRecordset, self).setUp() self.ensure_tld_exists('com') self.zone = self.useFixture(ZoneFixture( name=random_zone_name(), email='test@example.com', )).zone name = random_a_recordset_name(self.zone.name) self.recordset = self.useFixture(RecordsetFixture( zone_id=self.zone.id, name=name, records='1.2.3.4', description='An a recordset', type='A', ttl=1234, )).recordset self.assertEqual(self.recordset.name, name) self.assertEqual(self.recordset.records, '1.2.3.4') self.assertEqual(self.recordset.description, 'An a recordset') self.assertEqual(self.recordset.type, 'A') self.assertEqual(self.recordset.ttl, '1234') def test_recordset_list(self): rsets = self.clients.recordset_list(self.zone.id) self.assertGreater(len(rsets), 0) def test_recordset_create_and_show(self): rset = self.clients.recordset_show(self.zone.id, self.recordset.id) self.assertTrue(hasattr(self.recordset, 'action')) self.assertTrue(hasattr(rset, 'action')) self.assertEqual(self.recordset.created_at, rset.created_at) self.assertEqual(self.recordset.description, rset.description) self.assertEqual(self.recordset.id, rset.id) self.assertEqual(self.recordset.name, rset.name) self.assertEqual(self.recordset.records, rset.records) self.assertEqual(self.recordset.status, rset.status) self.assertEqual(self.recordset.ttl, rset.ttl) self.assertEqual(self.recordset.type, rset.type) self.assertEqual(self.recordset.updated_at, rset.updated_at) self.assertEqual(self.recordset.version, rset.version) self.assertEqual(self.recordset.zone_id, self.zone.id) def test_recordset_delete(self): rset = self.clients.recordset_delete(self.zone.id, self.recordset.id) self.assertEqual(rset.action, 'DELETE') self.assertEqual(rset.status, 'PENDING') def test_recordset_set(self): rset = self.clients.recordset_set( self.zone.id, self.recordset.id, records='2.3.4.5', ttl=2345, description='Updated description', ) self.assertEqual(rset.records, '2.3.4.5') self.assertEqual(rset.ttl, '2345') self.assertEqual(rset.description, 'Updated description') def test_recordset_set_clear_ttl_and_description(self): rset = self.clients.recordset_set( self.zone.id, self.recordset.id, no_description=True, no_ttl=True, ) self.assertEqual(rset.description, 'None') self.assertEqual(rset.ttl, 'None') class TestRecordsetNegative(BaseDesignateTest): def test_invalid_option_on_recordset_create(self): cmd = 'recordset create de47d30b-41c5-4e38-b2c5-e0b908e19ec7 ' \ 'aaa.desig.com. --type A --records 1.2.3.4 ' \ '--invalid "not valid"' self.assertRaises(CommandFailed, self.clients.openstack, cmd) def test_invalid_recordset_command(self): cmd = 'recordset hopefullynotvalid' self.assertRaises(CommandFailed, self.clients.openstack, cmd) python-designateclient-2.11.0/designateclient/functionaltests/v2/test_blacklist.py0000666000175000017500000000766013366577761030635 0ustar zuulzuul00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest.lib.exceptions import CommandFailed from designateclient.functionaltests.base import BaseDesignateTest from designateclient.functionaltests.datagen import random_blacklist from designateclient.functionaltests.v2.fixtures import BlacklistFixture class TestBlacklist(BaseDesignateTest): def setUp(self): super(TestBlacklist, self).setUp() pattern = random_blacklist() self.blacklist = self.useFixture(BlacklistFixture( pattern=pattern, description='A random blacklist', )).blacklist self.assertEqual(self.blacklist.pattern, pattern) self.assertEqual(self.blacklist.description, 'A random blacklist') def test_zone_blacklist_list(self): blacklists = self.clients.as_user('admin').zone_blacklist_list() self.assertGreater(len(blacklists), 0) def test_zone_blacklist_create_and_show(self): client = self.clients.as_user('admin') blacklist = client.zone_blacklist_show(self.blacklist.id) self.assertEqual(self.blacklist.created_at, blacklist.created_at) self.assertEqual(self.blacklist.description, blacklist.description) self.assertEqual(self.blacklist.id, blacklist.id) self.assertEqual(self.blacklist.pattern, blacklist.pattern) self.assertEqual(self.blacklist.updated_at, blacklist.updated_at) def test_zone_blacklist_delete(self): client = self.clients.as_user('admin') client.zone_blacklist_delete(self.blacklist.id) self.assertRaises(CommandFailed, client.zone_blacklist_show, self.blacklist.id) def test_zone_blacklist_set(self): client = self.clients.as_user('admin') updated_pattern = random_blacklist('updatedblacklist') blacklist = client.zone_blacklist_set( id=self.blacklist.id, pattern=updated_pattern, description='An updated blacklist', ) self.assertEqual(blacklist.created_at, self.blacklist.created_at) self.assertEqual(blacklist.description, 'An updated blacklist') self.assertEqual(blacklist.id, self.blacklist.id) self.assertEqual(blacklist.pattern, updated_pattern) self.assertNotEqual(blacklist.updated_at, self.blacklist.updated_at) def test_zone_blacklist_set_no_description(self): client = self.clients.as_user('admin') blacklist = client.zone_blacklist_set( id=self.blacklist.id, no_description=True, ) self.assertEqual(blacklist.description, 'None') def test_cannot_set_description_with_no_description_flag(self): client = self.clients.as_user('admin') self.assertRaises(CommandFailed, client.zone_blacklist_set, self.blacklist.id, pattern=random_blacklist(), description='new description', no_description=True) class TestBlacklistNegative(BaseDesignateTest): def test_invalid_blacklist_command(self): client = self.clients.as_user('admin') cmd = 'zone blacklist notacommand' self.assertRaises(CommandFailed, client.openstack, cmd) def test_blacklist_create_invalid_flag(self): client = self.clients.as_user('admin') cmd = 'zone blacklist create --pattern helloworld --notaflag invalid' self.assertRaises(CommandFailed, client.openstack, cmd) python-designateclient-2.11.0/designateclient/functionaltests/v2/test_zone_import.py0000666000175000017500000000472713366577761031233 0ustar zuulzuul00000000000000""" Copyright 2016 Rackspace Author: Rahman Syed Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from designateclient.functionaltests.base import BaseDesignateTest from designateclient.functionaltests.datagen import random_zone_file from designateclient.functionaltests.v2.fixtures import ImportFixture class TestZoneImport(BaseDesignateTest): def setUp(self): super(TestZoneImport, self).setUp() self.ensure_tld_exists('com') self.zone_file_contents = random_zone_file() def test_list_zone_imports(self): zone_import = self.useFixture(ImportFixture( zone_file_contents=self.zone_file_contents )).zone_import zone_imports = self.clients.zone_import_list() self.assertGreater(len(zone_imports), 0) self.assertTrue(self._is_entity_in_list(zone_import, zone_imports)) def test_create_and_show_zone_import(self): zone_import = self.useFixture(ImportFixture( zone_file_contents=self.zone_file_contents )).zone_import fetched_import = self.clients.zone_import_show(zone_import.id) self.assertEqual(zone_import.created_at, fetched_import.created_at) self.assertEqual(zone_import.id, fetched_import.id) self.assertEqual(zone_import.project_id, fetched_import.project_id) # check both statuses to avoid a race condition, causing test failure. # we don't know when the import completes. self.assertIn(fetched_import.status, ['PENDING', 'COMPLETE']) def test_delete_zone_import(self): zone_import = self.useFixture(ImportFixture( zone_file_contents=self.zone_file_contents )).zone_import zone_imports = self.clients.zone_import_list() self.assertTrue(self._is_entity_in_list(zone_import, zone_imports)) self.clients.zone_import_delete(zone_import.id) zone_imports = self.clients.zone_import_list() self.assertFalse(self._is_entity_in_list(zone_import, zone_imports)) python-designateclient-2.11.0/designateclient/osc/0000775000175000017500000000000013366600247022233 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/osc/__init__.py0000666000175000017500000000000013366577761024352 0ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/osc/plugin.py0000666000175000017500000000312013366577761024117 0ustar zuulzuul00000000000000# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """OpenStackClient plugin for DNS service.""" from osc_lib import utils as oscutils from designateclient import shell DEFAULT_API_VERSION = '2' API_NAME = 'dns' API_VERSION_OPTION = 'os_dns_api_version' API_VERSIONS = { '2': 'designateclient.v2.client.Client', } def make_client(instance): cls = oscutils.get_client_class( API_NAME, instance._api_version[API_NAME], API_VERSIONS) kwargs = oscutils.build_kwargs_dict('endpoint_type', instance._interface) return cls(session=instance.session, region_name=instance._region_name, **kwargs) def build_option_parser(parser): """Hook to add global options.""" parser.add_argument( '--os-dns-api-version', metavar='', default=shell.env('OS_DNS_API_VERSION', default="2"), help='DNS API version, default=' + DEFAULT_API_VERSION + ' (Env: OS_DNS_API_VERSION)') return parser python-designateclient-2.11.0/designateclient/tests/0000775000175000017500000000000013366600247022611 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/tests/test_utils.py0000666000175000017500000000626013366577761025406 0ustar zuulzuul00000000000000# Copyright (c) 2015 Thales Services SAS # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid import mock from designateclient import exceptions from designateclient.tests import base from designateclient import utils LIST_MOCK_RESPONSE = [ {'id': '13579bdf-0000-0000-abcd-000000000001', 'name': 'abcd'}, {'id': '13579bdf-0000-0000-baba-000000000001', 'name': 'baba'}, {'id': '13579bdf-0000-0000-baba-000000000002', 'name': 'baba'}, ] class UtilsTestCase(base.TestCase): def _find_resourceid_by_name_or_id(self, name_or_id, by_name=False): resource_client = mock.Mock() resource_client.list.return_value = LIST_MOCK_RESPONSE resourceid = utils.find_resourceid_by_name_or_id( resource_client, name_or_id) self.assertEqual(by_name, resource_client.list.called) return resourceid def test_find_resourceid_with_hyphen_uuid(self): expected = str(uuid.uuid4()) observed = self._find_resourceid_by_name_or_id(expected) self.assertEqual(expected, observed) def test_find_resourceid_with_nonhyphen_uuid(self): expected = str(uuid.uuid4()) fakeid = expected.replace('-', '') observed = self._find_resourceid_by_name_or_id(fakeid) self.assertEqual(expected, observed) def test_find_resourceid_with_unique_resource(self): observed = self._find_resourceid_by_name_or_id('abcd', by_name=True) self.assertEqual('13579bdf-0000-0000-abcd-000000000001', observed) def test_find_resourceid_with_nonexistent_resource(self): self.assertRaises(exceptions.ResourceNotFound, self._find_resourceid_by_name_or_id, 'taz', by_name=True) def test_find_resourceid_with_multiple_resources(self): self.assertRaises(exceptions.NoUniqueMatch, self._find_resourceid_by_name_or_id, 'baba', by_name=True) def test_load_schema(self): schema = utils.load_schema('v1', 'domain') self.assertIsInstance(schema, dict) def test_load_schema_missing(self): self.assertRaises(exceptions.ResourceNotFound, utils.load_schema, 'v1', 'missing') def test_resource_string_empty_param(self): self.assertRaises(ValueError, utils.resource_string) def test_resource_string(self): name = ['schemas', 'v1', 'domain.json'] resource_string = utils.resource_string(*name) self.assertIsNotNone(resource_string) def test_resource_string_missing(self): name = ['schemas', 'v1', 'missing'] self.assertRaises(exceptions.ResourceNotFound, utils.resource_string, *name) python-designateclient-2.11.0/designateclient/tests/__init__.py0000666000175000017500000000000013366577761024730 0ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/tests/test_v1/0000775000175000017500000000000013366600247024176 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/tests/test_v1/__init__.py0000666000175000017500000000274513366577761026337 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from designateclient.tests import base class CrudMixin(object): path_prefix = None def new_ref(self, **kwargs): kwargs.setdefault('id', uuid.uuid4().hex) return kwargs def stub_entity(self, method, parts=None, entity=None, id=None, **kwargs): if entity: kwargs['json'] = entity if not parts: parts = [self.RESOURCE] if self.path_prefix: parts.insert(0, self.path_prefix) if id: if not parts: parts = [] parts.append(id) self.stub_url(method, parts=parts, **kwargs) def assertList(self, expected, actual): self.assertEqual(len(expected), len(actual)) for i in expected: self.assertIn(i, actual) class APIV1TestCase(base.APITestCase): VERSION = "1" python-designateclient-2.11.0/designateclient/tests/test_v1/test_client.py0000666000175000017500000001030013366577761027077 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.tests import test_v1 from designateclient import utils from designateclient import v1 from keystoneauth1 import session as keystone_session class TestClient(test_v1.APIV1TestCase): def test_all_tenants(self): # Create a client with the all_tenants flag set to True client = v1.Client(all_tenants=True) # Verify this has been picked up self.assertTrue(client.all_tenants) def test_all_tenants_not_supplied(self): # Create a client without supplying any all_tenants flag client = v1.Client() # Verify all_tenants is False self.assertFalse(client.all_tenants) self.assertIsNotNone(client.all_tenants) def test_all_tenants_through_session(self): # Create a session with the all_tenants flag set to True session = utils.get_session( auth_url='Anything', endpoint='Anything', domain_id='Anything', domain_name='Anything', project_id='Anything', project_name='Anything', project_domain_name='Anything', project_domain_id='Anything', username='Anything', user_id='Anything', password='Anything', user_domain_id='Anything', user_domain_name='Anything', token=None, insecure=False, cacert=None, all_tenants=True) # Create a client using the pre-created session client = v1.Client(session=session) # Verify the all_tenants flag has been picked up self.assertTrue(client.all_tenants) def test_edit_managed(self): # Create a client with the edit_managed flag set to True client = v1.Client(edit_managed=True) # Verify this has been picked up self.assertTrue(client.edit_managed) def test_edit_managed_not_supplied(self): # Create a client without supplying any edit_managed flag client = v1.Client() # Verify edit_managed is False self.assertFalse(client.edit_managed) self.assertIsNotNone(client.edit_managed) def test_edit_managed_through_session(self): # Create a session with the edit_managed flag set to True session = utils.get_session( auth_url='Anything', endpoint='Anything', domain_id='Anything', domain_name='Anything', project_id='Anything', project_name='Anything', project_domain_name='Anything', project_domain_id='Anything', username='Anything', user_id='Anything', password='Anything', user_domain_id='Anything', user_domain_name='Anything', token=None, insecure=False, cacert=None, edit_managed=True) # Create a client using the pre-created session client = v1.Client(session=session) # Verify the edit_managed flag has been picked up self.assertTrue(client.edit_managed) def test_timeout_new_session(self): client = v1.Client( auth_url="http://127.0.0.1:22/", timeout=1, ) assert client.session.timeout == 1 def test_timeout_override_session_timeout(self): # The adapter timeout should override the session timeout session = keystone_session.Session(timeout=10) client = v1.Client( auth_url="http://127.0.0.1:22/", session=session, timeout=2, ) self.assertEqual(2, client.session.timeout) python-designateclient-2.11.0/designateclient/tests/test_v1/test_diagnostics.py0000666000175000017500000000215713366577761030143 0ustar zuulzuul00000000000000# Copyright 2015 NEC Corporation. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from mock import patch from designateclient.tests import test_v1 from designateclient.v1 import diagnostics class TestDiagnostics(test_v1.APIV1TestCase, test_v1.CrudMixin): @patch.object(diagnostics.DiagnosticsController, "ping") def test_ping(self, ping): args = mock.MagicMock() args.service = "foo" args.host = "host1" self.client.diagnostics.ping(args.host, args.service) self.client.diagnostics.ping.assert_called_with("host1", "foo") python-designateclient-2.11.0/designateclient/tests/test_v1/test_servers.py0000666000175000017500000000603213366577761027321 0ustar zuulzuul00000000000000# Copyright 2015 NEC Corporation. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid import mock from mock import patch from designateclient.tests import test_v1 from designateclient.v1 import servers class TestServers(test_v1.APIV1TestCase, test_v1.CrudMixin): RESOURCE = 'servers' def new_ref(self, **kwargs): ref = super(TestServers, self).new_ref(**kwargs) ref.setdefault("name", uuid.uuid4().hex) return ref def test_list(self): items = [ self.new_ref(name="ns1.example.org.", id="89acac79-38e7-497d-807c-a011e1310438"), self.new_ref(name="ns2.example.org.", id="89acac79-38e7-497d-807c-a011e1310435") ] self.stub_url("GET", parts=[self.RESOURCE], json={"servers": items}) listed = self.client.servers.list() self.assertList(items, listed) self.assertQueryStringIs("") def test_get(self): ref = self.new_ref(name="ns1.example.org.", id="89acac79-38e7-497d-807c-a011e1310438") self.stub_entity("GET", entity=ref, id=ref["id"]) response = self.client.servers.get(ref["id"]) self.assertEqual(ref, response) def test_create(self): ref = {"id": "89acac79-38e7-497d-807c-a011e1310438", "name": "ns1.example.org."} self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.servers.create({"name": "ns1.example.org."}) self.assertRequestBodyIs(json=values) def test_create_with_name_too_long(self): ref = {"id": "89acac79-38e7-497d-807c-a011e1310438", "name": "ns1." + "foo" * 85 + ".org."} self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.assertRaises(ValueError, self.client.servers.create, {"name": "ns1.example.org."}) @patch.object(servers.ServersController, "update") def test_update(self, server_update): ref = self.new_ref() self.stub_entity("PUT", entity=ref, id=ref["id"]) mock_server = mock.MagicMock() self.client.servers.update(mock_server) self.client.servers.update.assert_called_with(mock_server) def test_delete(self): ref = self.new_ref() self.stub_entity("DELETE", id=ref["id"]) self.client.servers.delete(ref["id"]) self.assertRequestBodyIs(None) python-designateclient-2.11.0/designateclient/tests/test_v1/test_domain.py0000666000175000017500000001421013366577761027074 0ustar zuulzuul00000000000000# Copyright 2015 NEC Corporation. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from mock import patch from designateclient.tests import test_v1 from designateclient import utils from designateclient.v1 import domains from designateclient import warlock Domain = warlock.model_factory(utils.load_schema('v1', 'domain')) class TestDomain(test_v1.APIV1TestCase, test_v1.CrudMixin): RESOURCE = 'domains' def new_ref(self, **kwargs): ref = super(TestDomain, self).new_ref(**kwargs) ref.setdefault("name", uuid.uuid4().hex) ref.setdefault("email", "abc@example.com.") ref.setdefault("ttl", 3600) return ref def test_create(self): ref = {"id": "89acac79-38e7-497d-807c-a011e1310438", "name": "domain1.com.", "email": "nsadmin@example.org", "ttl": 60} self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] response = self.client.domains.create(values["name"]) self.assertEqual(ref['id'], response['id']) def test_create_with_description(self): ref = {"id": "89acac79-38e7-497d-807c-a011e1310438", "name": "domain1.com.", "email": "nsadmin@example.org", "ttl": 60, "description": "fully qualified domain"} self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] response = self.client.domains.create(values["name"]) self.assertEqual(ref['id'], response['id']) def test_create_with_description_too_long(self): ref = {"id": "89acac79-38e7-497d-807c-a011e1310438", "name": "domain1.com.", "email": "nsadmin@example.org", "ttl": 60, "description": "d" * 161} self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.assertRaises(ValueError, self.client.domains.create, values["name"]) def test_create_with_zero_ttl(self): ref = {"id": "89acac79-38e7-497d-807c-a011e1310438", "name": "domain1.com.", "email": "nsadmin@example.org", "ttl": 0} self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.assertRaises(ValueError, self.client.domains.create, values["name"]) def test_create_with_negative_ttl(self): ref = {"id": "89acac79-38e7-497d-807c-a011e1310438", "name": "domain1.com.", "email": "nsadmin@example.org", "ttl": -1} self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.assertRaises(ValueError, self.client.domains.create, values["name"]) def test_create_with_no_ttl(self): ref = {"id": "89acac79-38e7-497d-807c-a011e1310438", "name": "domain1.com.", "email": "nsadmin@example.org", "ttl": ""} self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.assertRaises(ValueError, self.client.domains.create, values["name"]) def test_create_with_name_too_long(self): ref = {"id": "89acac79-38e7-497d-807c-a011e1310438", "name": "domain" + "a" * 255 + ".com.", "email": "nsadmin@example.org", "ttl": 60} self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.assertRaises(ValueError, self.client.domains.create, values["name"]) def test_list(self): items = [ self.new_ref(email="abc@example.org", id="89acac79-38e7-497d-807c-a011e1310438"), self.new_ref(email="root@example.org", id="89acac79-38e7-497d-807c-a011e1310435") ] self.stub_url("GET", parts=[self.RESOURCE], json={"domains": items}) listed = self.client.domains.list() self.assertList(items, listed) self.assertQueryStringIs("") def test_get(self): ref = self.new_ref(email="abc@example.org", id="89acac79-38e7-497d-807c-a011e1310438") self.stub_entity("GET", entity=ref, id=ref["id"]) response = self.client.domains.get(ref["id"]) self.assertEqual(ref, response) def test_delete(self): ref = self.new_ref(email="abc@example.org", id="89acac79-38e7-497d-807c-a011e1310438") self.stub_entity("DELETE", entity=ref, id=ref["id"]) self.client.domains.delete(ref["id"]) self.assertRequestBodyIs(None) def test_update(self): ref = self.new_ref(id="89acac79-38e7-497d-807c-a011e1310438") self.stub_entity("PUT", entity=ref, id=ref["id"]) values = ref.copy() self.client.domains.update(Domain(values)) @patch.object(domains.DomainsController, "list_domain_servers") def test_list_domain_servers(self, domains_get): domains_get.return_value = [{"id": "foo", "name": "ns1.example.com."}] ref = [{ "id": "foo", "name": "ns1.example.com.", }] parts = ["domains", "foo", "servers"] self.stub_url("GET", parts=parts, json={"servers": ref}) response = self.client.domains.list_domain_servers("foo") self.assertEqual(ref, response) python-designateclient-2.11.0/designateclient/tests/test_v1/test_touch.py0000666000175000017500000000205313366577761026751 0ustar zuulzuul00000000000000# Copyright 2015 NEC Corporation. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from mock import patch from designateclient.tests import test_v1 from designateclient.v1 import touch class TestTouch(test_v1.APIV1TestCase, test_v1.CrudMixin): @patch.object(touch.TouchController, "domain") def test_domain(self, domain): args = mock.MagicMock() args.domain_id = "1234" self.client.touch.domain(args.domain_id) self.client.touch.domain.assert_called_with("1234") python-designateclient-2.11.0/designateclient/tests/test_v1/test_sync.py0000666000175000017500000000310513366577761026602 0ustar zuulzuul00000000000000# Copyright 2015 NEC Corporation. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from mock import patch from designateclient.tests import test_v1 from designateclient.v1 import sync class TestSync(test_v1.APIV1TestCase, test_v1.CrudMixin): @patch.object(sync.SyncController, "sync_all") def test_sync_all(self, sync_all): self.client.sync.sync_all() self.client.sync.sync_all.assert_called_with() @patch.object(sync.SyncController, "sync_domain") def test_sync_domain(self, sync_domain): args = mock.MagicMock() args.tenant_id = "1234" self.client.sync.sync_domain(args.tenant_id) self.client.sync.sync_domain.assert_called_with("1234") @patch.object(sync.SyncController, "sync_record") def test_sync_record(self, sync_record): args = mock.MagicMock() args.tenant_id = "1234" args.record_id = "uuid" self.client.sync.sync_record(args.tenant_id, args.record_id) self.client.sync.sync_record.assert_called_with("1234", "uuid") python-designateclient-2.11.0/designateclient/tests/test_v1/test_quotas.py0000666000175000017500000000346013366577761027146 0ustar zuulzuul00000000000000# Copyright 2015 NEC Corporation. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from mock import patch from designateclient.tests import test_v1 from designateclient.v1 import quotas class TestQuota(test_v1.APIV1TestCase, test_v1.CrudMixin): @patch.object(quotas.QuotasController, "get") def test_get(self, quota_get): QUOTA = {"domains": 10, "recordset_records": 20, "domain_records": 500, "domain_recordsets": 500} quota_get.return_value = QUOTA response = self.client.quotas.get("foo") self.assertEqual(QUOTA, response) @patch.object(quotas.QuotasController, "update") def test_update(self, quota_update): args = mock.MagicMock() args.tenant_id = "1234" args.value = {"domains": 1000} self.client.quotas.update(args.tenant_id, args.value) self.client.quotas.update.assert_called_with(args.tenant_id, args.value) @patch.object(quotas.QuotasController, "reset") def test_reset(self, quota_reset): args = mock.MagicMock() args.tenant_id = "1234" self.client.quotas.reset(args.tenant_id) self.client.quotas.reset.assert_called_with("1234") python-designateclient-2.11.0/designateclient/tests/test_v1/test_records.py0000666000175000017500000001655613366577761027305 0ustar zuulzuul00000000000000# Copyright 2015 NEC Corporation. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from designateclient.tests import test_v1 from designateclient import utils from designateclient import warlock Record = warlock.model_factory(utils.load_schema('v1', 'record')) DOMAIN = { "id": str(uuid.uuid4()), "name": "example.com." } class TestRecords(test_v1.APIV1TestCase, test_v1.CrudMixin): RESOURCE = 'records' def new_ref(self, **kwargs): ref = super(TestRecords, self).new_ref(**kwargs) ref.setdefault("name", uuid.uuid4().hex) ref.setdefault("type", "A") ref.setdefault("data", "10.0.0.1") return ref def test_create_record(self): ref = self.new_ref(id="2e32e609-3a4f-45ba-bdef-e50eacd345ad") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_create_AAAA_record(self): ref = self.new_ref(id="11112222-3333-4444-5555-666677778888", type="AAAA", data="2001:db8:0:1234:0:5678:9:12") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_create_MX_record(self): ref = self.new_ref(id="11112222-3333-4444-5555-666677778989", type="MX", data="mail.example.com.", priority=10) parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_create_CNAME_record(self): ref = self.new_ref(id="11112222-3333-4444-5555-666677778890", type="CNAME", data="example.com.") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_create_TXT_record(self): ref = self.new_ref(id="11112222-3333-4444-5555-666677778889", type="TXT", data="This is a TXT record") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_create_SRV_record(self): ref = self.new_ref(id="11112222-3333-4444-5555-666677778888", type="SRV", data="0 5060 sip.example.com.", priority=30) parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_create_NS_record(self): ref = self.new_ref(id="11112222-3333-4444-5555-666677779999", type="NS", data="ns1.example.com.") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_create_PTR_record(self): ref = self.new_ref(id="11112222-3333-4444-5555-666677778891", type="PTR", data="www.example.com.") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_create_SPF_record(self): ref = self.new_ref(id="11112222-3333-4444-5555-666677778899", type="SPF", data="v=spf1 +mx a:colo.example.com/28 -all") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_create_SSHFP_record(self): ref = self.new_ref(id="11112222-3333-4444-5555-666677778888", type="SSHFP", data="2 1 6c3c958af43d953f91f40e0d84157f4fe7b4a898") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.records.create(DOMAIN['id'], Record(values)) self.assertRequestBodyIs(json=values) def test_get(self): ref = self.new_ref(id="2e32e609-3a4f-45ba-bdef-e50eacd345ad") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_entity("GET", entity=ref, id=ref["id"], parts=parts) response = self.client.records.get(DOMAIN["id"], ref["id"]) self.assertEqual(ref, response) def test_list(self): items = [ self.new_ref(id="2e32e609-3a4f-45ba-bdef-e50eacd345ad"), self.new_ref(id="11112222-3333-4444-5555-666677778888") ] parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_url("GET", parts=parts, json={"records": items}) listed = self.client.records.list(DOMAIN["id"]) self.assertList(items, listed) self.assertQueryStringIs("") def test_update(self): ref = self.new_ref(id="2e32e609-3a4f-45ba-bdef-e50eacd345ad", type="A", data="192.0.2.5") parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_entity("PUT", entity=ref, id=ref["id"], parts=parts) values = ref.copy() del values["id"] self.client.records.update(DOMAIN["id"], Record(ref)) def test_delete(self): ref = self.new_ref() parts = ["domains", DOMAIN["id"], self.RESOURCE] self.stub_entity("DELETE", id=ref["id"], parts=parts) self.client.records.delete(DOMAIN["id"], ref["id"]) self.assertRequestBodyIs(None) python-designateclient-2.11.0/designateclient/tests/test_v1/test_reports.py0000666000175000017500000000425413366577761027332 0ustar zuulzuul00000000000000# Copyright 2015 NEC Corporation. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from mock import patch from designateclient.tests import test_v1 from designateclient.v1 import reports class TestReports(test_v1.APIV1TestCase, test_v1.CrudMixin): @patch.object(reports.ReportsController, "count_all") def test_count_all(self, count_all): self.client.reports.count_all() self.client.reports.count_all.assert_called_with() @patch.object(reports.ReportsController, "count_domains") def test_count_domain(self, count_domains): self.client.reports.count_domains() self.client.reports.count_domains.assert_called_once_with() @patch.object(reports.ReportsController, "count_tenants") def test_count_tenants(self, count_tenants): self.client.reports.count_tenants() self.client.reports.count_tenants.assert_called_once_with() @patch.object(reports.ReportsController, "count_records") def test_count_records(self, count_records): self.client.reports.count_records() self.client.reports.count_records.assert_called_once_with() @patch.object(reports.ReportsController, "tenants_all") def test_tenants_all(self, tenants_all): self.client.reports.tenants_all() self.client.reports.tenants_all.assert_called_once_with() @patch.object(reports.ReportsController, "tenant_domains") def test_tenant_domains(self, tenant_domains): args = mock.MagicMock() args.other_tenant_id = "uuid" self.client.reports.tenant_domains(args.other_tenant_id) self.client.reports.tenant_domains.assert_called_once_with("uuid") python-designateclient-2.11.0/designateclient/tests/test_exceptions.py0000666000175000017500000000447013366577761026430 0ustar zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Author: James Li # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient import exceptions from designateclient.tests import base class RemoteErrorTestCase(base.TestCase): response_dict = { 'message': None, 'code': 500, 'type': None, 'errors': None, 'request_id': 1234 } def test_get_error_message(self): expected_msg = 'something wrong' self.response_dict['message'] = expected_msg remote_err = exceptions.RemoteError(**self.response_dict) self.assertEqual(expected_msg, remote_err.message) def test_get_error_message_with_errors(self): expected_msg = "u'nodot.com' is not a 'domainname'" errors = {"errors": [ {"path": ["name"], "message": expected_msg, "validator": "format", "validator_value": "domainname"} ] } self.response_dict['message'] = None self.response_dict['errors'] = errors remote_err = exceptions.RemoteError(**self.response_dict) self.assertEqual(expected_msg, remote_err.message) def test_get_error_message_with_type(self): expected_msg = 'invalid_object' self.response_dict['message'] = None self.response_dict['errors'] = None self.response_dict['type'] = expected_msg remote_err = exceptions.RemoteError(**self.response_dict) self.assertEqual(expected_msg, remote_err.message) def test_get_error_message_with_unknown_response(self): expected_msg = 'invalid_object' self.response_dict['message'] = expected_msg self.response_dict['unknown'] = 'fake' remote_err = exceptions.RemoteError(**self.response_dict) self.assertEqual(expected_msg, remote_err.message) python-designateclient-2.11.0/designateclient/tests/base.py0000666000175000017500000001243413366577761024121 0ustar zuulzuul00000000000000# Copyright 2010-2011 OpenStack Foundation # Copyright (c) 2015 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json as json_ import os import fixtures from keystoneauth1 import session as keystone_session from oslotest import base as test from requests_mock.contrib import fixture as req_fixture import six from six.moves.urllib import parse as urlparse from designateclient import client from designateclient.utils import AdapterWithTimeout _TRUE_VALUES = ('True', 'true', '1', 'yes') class TestCase(test.BaseTestCase): """Test case base class for all unit tests.""" def setUp(self): """Run before each test method to initialize test environment.""" super(TestCase, self).setUp() test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) try: test_timeout = int(test_timeout) except ValueError: # If timeout value is invalid do not set a timeout. test_timeout = 0 if test_timeout > 0: self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) self.useFixture(fixtures.NestedTempfile()) self.useFixture(fixtures.TempHomeDir()) if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES: stdout = self.useFixture(fixtures.StringStream('stdout')).stream self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES: stderr = self.useFixture(fixtures.StringStream('stderr')).stream self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) self.log_fixture = self.useFixture(fixtures.FakeLogger()) class APITestCase(TestCase): """Test case base class for all unit tests.""" TEST_URL = "http://127.0.0.1:9001/" VERSION = None def setUp(self): """Run before each test method to initialize test environment.""" super(TestCase, self).setUp() self.log_fixture = self.useFixture(fixtures.FakeLogger()) self.requests = self.useFixture(req_fixture.Fixture()) self.client = self.get_client() def get_base(self, base_url=None): if not base_url: base_url = '%sv%s' % (self.TEST_URL, self.VERSION) return base_url def stub_url(self, method, parts=None, base_url=None, json=None, **kwargs): base_url = self.get_base(base_url) if json: kwargs['text'] = json_.dumps(json) headers = kwargs.setdefault('headers', {}) headers['Content-Type'] = 'application/json' if parts: url = '/'.join([p.strip('/') for p in [base_url] + parts]) else: url = base_url url = url.replace("/?", "?") self.requests.register_uri(method, url, **kwargs) def get_client(self, version=None, session=None): version = version or self.VERSION session = session or keystone_session.Session() adapted = AdapterWithTimeout( session=session, endpoint_override=self.get_base()) return client.Client(version, session=adapted) def assertRequestBodyIs(self, body=None, json=None): last_request_body = self.requests.last_request.body if json: val = json_.loads(last_request_body) self.assertEqual(json, val) elif body: self.assertEqual(body, last_request_body) def assertQueryStringIs(self, qs=''): """Verify the QueryString matches what is expected. The qs parameter should be of the format \'foo=bar&abc=xyz\' """ expected = urlparse.parse_qs(qs, keep_blank_values=True) parts = urlparse.urlparse(self.requests.last_request.url) querystring = urlparse.parse_qs(parts.query, keep_blank_values=True) self.assertEqual(expected, querystring) def assertQueryStringContains(self, **kwargs): """Verify the query string contains the expected parameters. This method is used to verify that the query string for the most recent request made contains all the parameters provided as ``kwargs``, and that the value of each parameter contains the value for the kwarg. If the value for the kwarg is an empty string (''), then all that's verified is that the parameter is present. """ parts = urlparse.urlparse(self.requests.last_request.url) qs = urlparse.parse_qs(parts.query, keep_blank_values=True) for k, v in six.iteritems(kwargs): self.assertIn(k, qs) self.assertIn(v, qs[k]) def assertRequestHeaderEqual(self, name, val): """Verify that the last request made contains a header and its value The request must have already been made. """ headers = self.requests.last_request.headers self.assertEqual(val, headers.get(name)) python-designateclient-2.11.0/designateclient/tests/test_designateclient.py0000666000175000017500000000152213366577761027404 0ustar zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ test_designateclient ---------------------------------- Tests for `designateclient` module. """ import designateclient from designateclient.tests import base class ClientTestCase(base.TestCase): def test_module_version(self): self.assertTrue(hasattr(designateclient, '__version__')) python-designateclient-2.11.0/designateclient/tests/v2/0000775000175000017500000000000013366600247023140 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/tests/v2/test_reverse.py0000666000175000017500000000344413366577761026251 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from designateclient.tests import v2 FIP_ID = '%s:%s' % (str(uuid.uuid4()), "RegionOne") class TestFloatingIP(v2.APIV2TestCase, v2.CrudMixin): def test_set(self): name = "foo.com." ref = { "ptrdname": name, "description": "foo" } parts = ["reverse", "floatingips", FIP_ID] self.stub_url("PATCH", parts=parts, json=ref) self.client.floatingips.set(FIP_ID, name, "foo") def test_list(self): ref = [ {"ptrdname": "foo.com."} ] self.stub_url("GET", parts=["reverse", "floatingips"], json={"floatingips": ref}) self.client.floatingips.list() def test_get(self): ref = { "ptrdname": "foo.com." } parts = ["reverse", "floatingips", FIP_ID] self.stub_url("GET", parts=parts, json=ref) self.client.floatingips.get(FIP_ID) def test_unset(self): parts = ["reverse", "floatingips", FIP_ID] self.stub_url("PATCH", parts=parts, json={"ptdrname": None}) self.client.floatingips.unset(FIP_ID) self.assertRequestBodyIs(None) python-designateclient-2.11.0/designateclient/tests/v2/test_tlds.py0000666000175000017500000000563113366577761025544 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from designateclient.tests import v2 class TestTlds(v2.APIV2TestCase, v2.CrudMixin): RESOURCE = 'tlds' def new_ref(self, **kwargs): ref = super(TestTlds, self).new_ref(**kwargs) ref.setdefault("name", uuid.uuid4().hex) return ref def test_create(self): ref = self.new_ref() self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.tlds.create(**values) self.assertRequestBodyIs(json=values) def test_create_with_description(self): ref = self.new_ref(description="My TLD") self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.tlds.create(**values) self.assertRequestBodyIs(json=values) def test_get(self): ref = self.new_ref() self.stub_entity("GET", entity=ref, id=ref["id"]) response = self.client.tlds.get(ref["id"]) self.assertEqual(ref, response) def test_get_by_name(self): ref = self.new_ref(name="www") self.stub_entity("GET", entity=ref, id=ref["id"]) self.stub_url("GET", parts=[self.RESOURCE], json={"tlds": [ref]}) response = self.client.tlds.get(ref['name']) self.assertEqual("GET", self.requests.request_history[0].method) self.assertEqual( "http://127.0.0.1:9001/v2/tlds?name=www", self.requests.request_history[0].url) self.assertEqual(ref, response) def test_list(self): items = [ self.new_ref(), self.new_ref() ] self.stub_url("GET", parts=[self.RESOURCE], json={"tlds": items}) listed = self.client.tlds.list() self.assertList(items, listed) self.assertQueryStringIs("") def test_update(self): ref = self.new_ref() self.stub_entity("PATCH", entity=ref, id=ref["id"]) values = ref.copy() del values["id"] self.client.tlds.update(ref["id"], values) self.assertRequestBodyIs(json=values) def test_delete(self): ref = self.new_ref() self.stub_entity("DELETE", id=ref["id"]) self.client.tlds.delete(ref["id"]) self.assertRequestBodyIs(None) python-designateclient-2.11.0/designateclient/tests/v2/test_timeout.py0000666000175000017500000000746113366577761026267 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Federico Ceratto # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session from mock import Mock from designateclient.tests import v2 from designateclient.v2.client import Client def create_session(timeout=None): auth = generic.Password(auth_url='', username='', password='', tenant_name='') return keystone_session.Session(auth=auth, timeout=timeout) class TestTimeout(v2.APIV2TestCase, v2.CrudMixin): def setUp(self): super(TestTimeout, self).setUp() # Mock methods in KeyStone's Session self._saved_methods = ( keystone_session.Session.get_auth_headers, keystone_session.Session.get_endpoint, keystone_session.Session._send_request, ) resp = Mock() resp.text = '' resp.status_code = 200 keystone_session.Session.get_auth_headers = Mock( return_value=[] ) keystone_session.Session.get_endpoint = Mock( return_value='foo' ) keystone_session.Session._send_request = Mock( return_value=resp, ) self.mock_send_request = keystone_session.Session._send_request def tearDown(self): super(TestTimeout, self).tearDown() ( keystone_session.Session.get_auth_headers, keystone_session.Session.get_endpoint, keystone_session.Session._send_request, ) = self._saved_methods def _call_request_and_check_timeout(self, client, timeout): """call the mocked _send_request() and check if the timeout was set """ client.limits.get() self.assertTrue(self.mock_send_request.called) kw = self.mock_send_request.call_args[1] if timeout is None: self.assertNotIn('timeout', kw) else: self.assertEqual(timeout, kw['timeout']) def test_no_timeout(self): session = create_session(timeout=None) client = Client(session=session) self.assertIsNone(session.timeout) self.assertIsNone(client.session.timeout) self._call_request_and_check_timeout(client, None) def test_timeout_in_session(self): session = create_session(timeout=1) client = Client(session=session) self.assertEqual(1, session.timeout) self.assertIsNone(client.session.timeout) self._call_request_and_check_timeout(client, 1) def test_timeout_override_session_timeout(self): # The adapter timeout should override the session timeout session = create_session(timeout=10) self.assertEqual(10, session.timeout) client = Client(session=session, timeout=2) self.assertEqual(2, client.session.timeout) self._call_request_and_check_timeout(client, 2) def test_timeout_update(self): session = create_session(timeout=1) client = Client(session=session) self.assertEqual(1, session.timeout) self.assertIsNone(client.session.timeout) self._call_request_and_check_timeout(client, 1) session.timeout = 2 self.assertEqual(2, session.timeout) self._call_request_and_check_timeout(client, 2) python-designateclient-2.11.0/designateclient/tests/v2/test_blacklists.py0000666000175000017500000000474613366577761026737 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from designateclient.tests import v2 class TestBlacklists(v2.APIV2TestCase, v2.CrudMixin): RESOURCE = 'blacklists' def new_ref(self, **kwargs): ref = super(TestBlacklists, self).new_ref(**kwargs) ref.setdefault("pattern", uuid.uuid4().hex) return ref def test_create(self): ref = self.new_ref() self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.blacklists.create(**values) self.assertRequestBodyIs(json=values) def test_create_with_description(self): ref = self.new_ref(description="My Blacklist") self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.blacklists.create(**values) self.assertRequestBodyIs(json=values) def test_get(self): ref = self.new_ref() self.stub_entity("GET", entity=ref, id=ref["id"]) response = self.client.blacklists.get(ref["id"]) self.assertEqual(ref, response) def test_list(self): items = [ self.new_ref(), self.new_ref() ] self.stub_url("GET", parts=[self.RESOURCE], json={"blacklists": items}) listed = self.client.blacklists.list() self.assertList(items, listed) self.assertQueryStringIs("") def test_update(self): ref = self.new_ref() self.stub_entity("PATCH", entity=ref, id=ref["id"]) values = ref.copy() del values["id"] self.client.blacklists.update(ref["id"], values) self.assertRequestBodyIs(json=values) def test_delete(self): ref = self.new_ref() self.stub_entity("DELETE", id=ref["id"]) self.client.blacklists.delete(ref["id"]) self.assertRequestBodyIs(None) python-designateclient-2.11.0/designateclient/tests/v2/__init__.py0000666000175000017500000000275313366577761025300 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from designateclient.tests import base class CrudMixin(object): path_prefix = None def new_ref(self, **kwargs): kwargs.setdefault('id', uuid.uuid4().hex) return kwargs def stub_entity(self, method, parts=None, entity=None, id=None, **kwargs): if entity: kwargs['json'] = entity if not parts: parts = [self.RESOURCE] if self.path_prefix: parts.insert(0, self.path_prefix) if id: if not parts: parts = [] parts.append(id) self.stub_url(method, parts=parts, **kwargs) def assertList(self, expected, actual): self.assertEqual(len(expected), len(actual)) for i in expected: self.assertIn(i, actual) class APIV2TestCase(base.APITestCase): VERSION = "2" python-designateclient-2.11.0/designateclient/tests/v2/test_limits.py0000666000175000017500000000165513366577761026101 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.tests import v2 class TestLimits(v2.APIV2TestCase, v2.CrudMixin): def test_get(self): ref = {"max_zones": "foo"} self.stub_url("GET", parts=["limits"], json=ref) limits = self.client.limits.get() self.assertEqual(ref, limits) python-designateclient-2.11.0/designateclient/tests/v2/test_client.py0000666000175000017500000000304613366577761026052 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Federico Ceratto # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from keystoneauth1 import adapter from keystoneauth1 import session as keystone_session from designateclient.tests.base import TestCase from designateclient.v2.client import Client class TestClient(TestCase): def test_init(self): self.assertRaises(ValueError, Client) def test_init_with_session(self): session = keystone_session.Session() adapted = adapter.Adapter(session=session) client = Client(session=adapted) assert client.session def test_init_with_session_timeout(self): session = keystone_session.Session() client = Client( session=session, timeout=1) assert client.session.timeout == 1 def test_init_with_auth(self): session = keystone_session.Session() client = Client( auth='http://127.0.0.1:22/', session=session) assert client.session.auth python-designateclient-2.11.0/designateclient/tests/v2/test_tsigkeys.py0000666000175000017500000000550013366577761026433 0ustar zuulzuul00000000000000# Copyright 2017 SAP SE # # Author: Rudolf Vriend # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from designateclient.tests import v2 class TestTSIGKeys(v2.APIV2TestCase, v2.CrudMixin): RESOURCE = 'tsigkeys' def new_ref(self, **kwargs): ref = super(TestTSIGKeys, self).new_ref(**kwargs) ref.setdefault("name", uuid.uuid4().hex) ref.setdefault("algorithm", "hmac-sha256") ref.setdefault("secret", uuid.uuid4().hex) ref.setdefault("scope", "POOL") ref.setdefault("resource_id", uuid.uuid4().hex) return ref def test_create(self): ref = self.new_ref() self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.tsigkeys.create(**values) self.assertRequestBodyIs(json=values) def test_get(self): ref = self.new_ref() self.stub_entity("GET", entity=ref, id=ref["id"]) response = self.client.tsigkeys.get(ref["id"]) self.assertEqual(ref, response) def test_get_by_name(self): ref = self.new_ref(name="www") self.stub_entity("GET", entity=ref, id=ref["id"]) self.stub_url("GET", parts=[self.RESOURCE], json={"tsigkeys": [ref]}) response = self.client.tsigkeys.get(ref['name']) self.assertEqual("GET", self.requests.request_history[0].method) self.assertEqual( "http://127.0.0.1:9001/v2/tsigkeys?name=www", self.requests.request_history[0].url) self.assertEqual(ref, response) def test_list(self): items = [ self.new_ref(), self.new_ref() ] self.stub_url("GET", parts=[self.RESOURCE], json={"tsigkeys": items}) listed = self.client.tsigkeys.list() self.assertList(items, listed) self.assertQueryStringIs("") def test_update(self): ref = self.new_ref() self.stub_entity("PATCH", entity=ref, id=ref["id"]) values = ref.copy() del values["id"] self.client.tsigkeys.update(ref["id"], values) self.assertRequestBodyIs(json=values) def test_delete(self): ref = self.new_ref() self.stub_entity("DELETE", id=ref["id"]) self.client.tsigkeys.delete(ref["id"]) self.assertRequestBodyIs(None) python-designateclient-2.11.0/designateclient/tests/v2/test_recordsets.py0000666000175000017500000001563513366577761026760 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from mock import patch import testtools from designateclient import exceptions from designateclient.tests import v2 from designateclient.v2 import zones ZONE = { "id": str(uuid.uuid4()), "name": "example.com." } class TestRecordSets(v2.APIV2TestCase, v2.CrudMixin): RESOURCE = 'recordsets' def new_ref(self, **kwargs): ref = super(TestRecordSets, self).new_ref(**kwargs) ref.setdefault("name", uuid.uuid4().hex) ref.setdefault("type", "A") ref.setdefault("records", ["10.0.0.1"]) return ref def test_create_absolute_with_zone_dict(self): ref = self.new_ref() parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.recordsets.create( ZONE, "%s.%s" % (values["name"], ZONE["name"]), values["type"], values["records"]) values["name"] = "%s.%s" % (ref["name"], ZONE["name"]) self.assertRequestBodyIs(json=values) @patch.object(zones.ZoneController, "get") def test_create_absolute_with_zone_name(self, zone_get): ref = self.new_ref() zone_get.return_value = ZONE parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.recordsets.create( ZONE["name"], "%s.%s" % (values["name"], ZONE["name"]), values["type"], values["records"]) values["name"] = "%s.%s" % (ref["name"], ZONE["name"]) self.assertRequestBodyIs(json=values) @patch.object(zones.ZoneController, "get") def test_create_non_absolute_with_zone_name(self, zone_get): ref = self.new_ref() zone_get.return_value = ZONE parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.recordsets.create( ZONE["name"], values["name"], values["type"], values["records"]) values["name"] = "%s.%s" % (ref["name"], ZONE["name"]) self.assertRequestBodyIs(json=values) @patch.object(zones.ZoneController, "list") def test_create_non_absolute_with_zone_name_non_unique(self, zone_list): zone_list.return_value = [ 1, 2 ] ref = self.new_ref() values = ref.copy() del values["id"] with testtools.ExpectedException(exceptions.NoUniqueMatch): self.client.recordsets.create( ZONE["name"], "%s.%s" % (values["name"], ZONE["name"]), values["type"], values["records"]) def test_create_absolute_with_zone_id(self): ref = self.new_ref() parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.recordsets.create( ZONE["id"], "%s.%s" % (values["name"], ZONE["name"]), values["type"], values["records"]) values["name"] = "%s.%s" % (ref["name"], ZONE["name"]) self.assertRequestBodyIs(json=values) @patch.object(zones.ZoneController, "get") def test_create_non_absolute_with_zone_id(self, zone_get): ref = self.new_ref() zone_get.return_value = ZONE parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.recordsets.create( ZONE["id"], values["name"], values["type"], values["records"]) values["name"] = "%s.%s" % (ref["name"], ZONE["name"]) self.assertRequestBodyIs(json=values) def test_create_with_description(self): ref = self.new_ref(description="Foo") parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.recordsets.create( ZONE["id"], "%s.%s" % (values["name"], ZONE["name"]), values["type"], values["records"], description=values["description"]) values["name"] = "%s.%s" % (ref["name"], ZONE["name"]) self.assertRequestBodyIs(json=values) def test_create_with_ttl(self): ref = self.new_ref(ttl=60) parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_url("POST", parts=parts, json=ref) values = ref.copy() del values["id"] self.client.recordsets.create( ZONE["id"], "%s.%s" % (values["name"], ZONE["name"]), values["type"], values["records"], ttl=values["ttl"]) values["name"] = "%s.%s" % (ref["name"], ZONE["name"]) self.assertRequestBodyIs(json=values) def test_get(self): ref = self.new_ref() parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_entity("GET", entity=ref, id=ref["id"], parts=parts) response = self.client.recordsets.get(ZONE["id"], ref["id"]) self.assertEqual(ref, response) def test_list(self): items = [ self.new_ref(), self.new_ref() ] parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_url("GET", parts=parts, json={"recordsets": items}) listed = self.client.recordsets.list(ZONE["id"]) self.assertList(items, listed) self.assertQueryStringIs("") def test_update(self): ref = self.new_ref() parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_entity("PUT", entity=ref, id=ref["id"], parts=parts) values = ref.copy() del values["id"] self.client.recordsets.update(ZONE["id"], ref["id"], values) self.assertRequestBodyIs(json=values) def test_delete(self): ref = self.new_ref() parts = ["zones", ZONE["id"], self.RESOURCE] self.stub_entity("DELETE", id=ref["id"], parts=parts) self.client.recordsets.delete(ZONE["id"], ref["id"]) self.assertRequestBodyIs(None) python-designateclient-2.11.0/designateclient/tests/v2/test_service_statuses.py0000666000175000017500000000274213366577761030171 0ustar zuulzuul00000000000000# Copyright 2016 Hewlett Packard Enterprise Development Company LP # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.tests import v2 class TestServiceStatuses(v2.APIV2TestCase, v2.CrudMixin): RESOURCE = 'service_statuses' def new_ref(self, **kwargs): ref = super(TestServiceStatuses, self).new_ref(**kwargs) ref["name"] = "foo" return ref def test_get(self): ref = self.new_ref() self.stub_entity("GET", entity=ref, id=ref["id"]) response = self.client.service_statuses.get(ref["id"]) self.assertEqual(ref, response) def test_list(self): items = [ self.new_ref(), self.new_ref() ] self.stub_url("GET", parts=[self.RESOURCE], json={"service_statuses": items}) listed = self.client.service_statuses.list() self.assertList(items, listed) self.assertQueryStringIs("") python-designateclient-2.11.0/designateclient/tests/v2/test_zones.py0000666000175000017500000002676713366577761025751 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import time import uuid from designateclient.tests import v2 class TestZones(v2.APIV2TestCase, v2.CrudMixin): RESOURCE = 'zones' def new_ref(self, **kwargs): ref = super(TestZones, self).new_ref(**kwargs) ref.setdefault("name", uuid.uuid4().hex) ref.setdefault("type", "PRIMARY") return ref def test_create_with_description(self): ref = self.new_ref(email="root@example.com", description="Foo") self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.zones.create( values["name"], email=values["email"], description=values["description"]) self.assertRequestBodyIs(json=values) def test_create_primary(self): ref = self.new_ref(email="root@example.com") self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.zones.create( values["name"], email=values["email"]) self.assertRequestBodyIs(json=values) def test_create_primary_with_ttl(self): ref = self.new_ref(email="root@example.com", ttl=60) self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.zones.create( values["name"], email=values["email"], ttl=values["ttl"]) self.assertRequestBodyIs(json=values) def test_create_secondary(self): ref = self.new_ref(type="SECONDARY", masters=["10.0.0.1"]) self.stub_url("POST", parts=[self.RESOURCE], json=ref) values = ref.copy() del values["id"] self.client.zones.create( values["name"], type_=values["type"], masters=values["masters"]) self.assertRequestBodyIs(json=values) def test_get(self): ref = self.new_ref() self.stub_entity("GET", entity=ref, id=ref["id"]) response = self.client.zones.get(ref["id"]) self.assertEqual(ref, response) def test_list(self): items = [ self.new_ref(), self.new_ref() ] self.stub_url("GET", parts=[self.RESOURCE], json={"zones": items}) listed = self.client.zones.list() self.assertList(items, listed) self.assertQueryStringIs("") def test_update(self): ref = self.new_ref() self.stub_entity("PATCH", entity=ref, id=ref["id"]) values = ref.copy() del values["id"] self.client.zones.update(ref["id"], values) self.assertRequestBodyIs(json=values) def test_delete(self): ref = self.new_ref() self.stub_entity("DELETE", id=ref["id"]) self.client.zones.delete(ref["id"]) self.assertRequestBodyIs(None) def test_task_abandon(self): ref = self.new_ref() parts = [self.RESOURCE, ref["id"], "tasks", "abandon"] self.stub_url("POST", parts=parts) self.client.zones.abandon(ref["id"]) self.assertRequestBodyIs(None) def test_task_axfr(self): ref = self.new_ref() parts = [self.RESOURCE, ref["id"], "tasks", "xfr"] self.stub_url("POST", parts=parts) self.client.zones.axfr(ref["id"]) self.assertRequestBodyIs(None) class TestZoneTransfers(v2.APIV2TestCase, v2.CrudMixin): def test_create_request(self): zone = "098bee04-fe30-4a83-8ccd-e0c496755816" project = "123" ref = { "target_project_id": project } parts = ["zones", zone, "tasks", "transfer_requests"] self.stub_url('POST', parts=parts, json=ref) self.client.zone_transfers.create_request(zone, project) self.assertRequestBodyIs(json=ref) def test_create_request_with_description(self): zone = "098bee04-fe30-4a83-8ccd-e0c496755816" project = "123" ref = { "target_project_id": project, "description": "My Foo" } parts = ["zones", zone, "tasks", "transfer_requests"] self.stub_url('POST', parts=parts, json=ref) self.client.zone_transfers.create_request( zone, project, ref["description"]) self.assertRequestBodyIs(json=ref) def test_get_request(self): transfer = "098bee04-fe30-4a83-8ccd-e0c496755816" project = "098bee04-fe30-4a83-8ccd-e0c496755817" ref = { "target_project_id": project } parts = ["zones", "tasks", "transfer_requests", transfer] self.stub_url('GET', parts=parts, json=ref) self.client.zone_transfers.get_request(transfer) self.assertRequestBodyIs("") def test_list_request(self): project = "098bee04-fe30-4a83-8ccd-e0c496755817" ref = [{ "target_project_id": project }] parts = ["zones", "tasks", "transfer_requests"] self.stub_url('GET', parts=parts, json={"transfer_requests": ref}) self.client.zone_transfers.list_requests() self.assertRequestBodyIs("") def test_update_request(self): transfer = "098bee04-fe30-4a83-8ccd-e0c496755816" project = "098bee04-fe30-4a83-8ccd-e0c496755817" ref = { "target_project_id": project } parts = ["zones", "tasks", "transfer_requests", transfer] self.stub_url('PATCH', parts=parts, json=ref) self.client.zone_transfers.update_request(transfer, ref) self.assertRequestBodyIs(json=ref) def test_delete_request(self): transfer = "098bee04-fe30-4a83-8ccd-e0c496755816" parts = ["zones", "tasks", "transfer_requests", transfer] self.stub_url('DELETE', parts=parts) self.client.zone_transfers.delete_request(transfer) self.assertRequestBodyIs("") def test_accept_request(self): transfer = "098bee04-fe30-4a83-8ccd-e0c496755816" key = "foo123" ref = { "status": "COMPLETE" } parts = ["zones", "tasks", "transfer_accepts"] self.stub_url('POST', parts=parts, json=ref) request = { "key": key, "zone_transfer_request_id": transfer } self.client.zone_transfers.accept_request(transfer, key) self.assertRequestBodyIs(json=request) def test_get_accept(self): accept_id = "098bee04-fe30-4a83-8ccd-e0c496755816" ref = { "status": "COMPLETE" } parts = ["zones", "tasks", "transfer_accepts", accept_id] self.stub_url('GET', parts=parts, json=ref) response = self.client.zone_transfers.get_accept(accept_id) self.assertEqual(ref, response) def test_list_accepts(self): accept_id = "098bee04-fe30-4a83-8ccd-e0c496755816" ref = { "id": accept_id, "status": "COMPLETE" } parts = ["zones", "tasks", "transfer_accepts"] self.stub_url('GET', parts=parts, json={"transfer_accepts": ref}) self.client.zone_transfers.list_accepts() self.assertRequestBodyIs("") class TestZoneExports(v2.APIV2TestCase, v2.CrudMixin): def new_ref(self, **kwargs): ref = super(TestZoneExports, self).new_ref(**kwargs) ref.setdefault("zone_id", uuid.uuid4().hex) ref.setdefault("created_at", time.strftime("%c")) ref.setdefault("updated_at", time.strftime("%c")) ref.setdefault("status", 'PENDING') ref.setdefault("version", '1') return ref def test_create_export(self): zone = uuid.uuid4().hex ref = {} parts = ["zones", zone, "tasks", "export"] self.stub_url('POST', parts=parts, json=ref) self.client.zone_exports.create(zone) self.assertRequestBodyIs(json=ref) def test_get_export(self): ref = self.new_ref() parts = ["zones", "tasks", "exports", ref["id"]] self.stub_url('GET', parts=parts, json=ref) self.stub_entity("GET", parts=parts, entity=ref, id=ref["id"]) response = self.client.zone_exports.get_export_record(ref["id"]) self.assertEqual(ref, response) def test_list_exports(self): items = [ self.new_ref(), self.new_ref() ] parts = ["zones", "tasks", "exports"] self.stub_url('GET', parts=parts, json={"exports": items}) listed = self.client.zone_exports.list() self.assertList(items, listed["exports"]) self.assertQueryStringIs("") def test_delete_export(self): ref = self.new_ref() parts = ["zones", "tasks", "exports", ref["id"]] self.stub_url('DELETE', parts=parts, json=ref) self.stub_entity("DELETE", parts=parts, id=ref["id"]) self.client.zone_exports.delete(ref["id"]) self.assertRequestBodyIs(None) def test_get_export_file(self): ref = self.new_ref() parts = ["zones", "tasks", "exports", ref["id"], "export"] self.stub_url('GET', parts=parts, json=ref) self.stub_entity("GET", parts=parts, entity=ref, id=ref["id"]) response = self.client.zone_exports.get_export(ref["id"]) self.assertEqual(ref, response) class TestZoneImports(v2.APIV2TestCase, v2.CrudMixin): def new_ref(self, **kwargs): ref = super(TestZoneImports, self).new_ref(**kwargs) ref.setdefault("zone_id", uuid.uuid4().hex) ref.setdefault("created_at", time.strftime("%c")) ref.setdefault("updated_at", time.strftime("%c")) ref.setdefault("status", 'PENDING') ref.setdefault("message", 'Importing...') ref.setdefault("version", '1') return ref def test_create_import(self): zonefile = '$ORIGIN example.com' parts = ["zones", "tasks", "imports"] self.stub_url('POST', parts=parts, json=zonefile) self.client.zone_imports.create(zonefile) self.assertRequestBodyIs(body=zonefile) def test_get_import(self): ref = self.new_ref() parts = ["zones", "tasks", "imports", ref["id"]] self.stub_url('GET', parts=parts, json=ref) self.stub_entity("GET", parts=parts, entity=ref, id=ref["id"]) response = self.client.zone_imports.get_import_record(ref["id"]) self.assertEqual(ref, response) def test_list_imports(self): items = [ self.new_ref(), self.new_ref() ] parts = ["zones", "tasks", "imports"] self.stub_url('GET', parts=parts, json={"imports": items}) listed = self.client.zone_imports.list() self.assertList(items, listed["imports"]) self.assertQueryStringIs("") def test_delete_import(self): ref = self.new_ref() parts = ["zones", "tasks", "imports", ref["id"]] self.stub_url('DELETE', parts=parts, json=ref) self.stub_entity("DELETE", parts=parts, id=ref["id"]) self.client.zone_imports.delete(ref["id"]) self.assertRequestBodyIs(None) python-designateclient-2.11.0/designateclient/tests/v2/test_nameservers.py0000666000175000017500000000234113366577761027123 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from mock import patch from designateclient.tests import v2 from designateclient.v2 import zones class TestLimits(v2.APIV2TestCase, v2.CrudMixin): @patch.object(zones.ZoneController, "list") def test_get(self, zones_get): zones_get.return_value = [{"id": "foo"}] ref = [{ "hostname": "ns1.example.com.", "priority": 1 }] parts = ["zones", "foo", "nameservers"] self.stub_url("GET", parts=parts, json={"nameservers": ref}) response = self.client.nameservers.list("foo") self.assertEqual(ref, response) python-designateclient-2.11.0/designateclient/v1/0000775000175000017500000000000013366600247021775 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/v1/servers.py0000666000175000017500000000436413366577761024067 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json from designateclient import client from designateclient import utils from designateclient import warlock Server = warlock.model_factory(utils.load_schema('v1', 'server')) class ServersController(client.CrudController): def list(self): """ Retrieve a list of servers :returns: A list of :class:`Server` """ response = self.client.get('/servers') return [Server(i) for i in response.json()['servers']] def get(self, server_id): """ Retrieve a server :param server_id: Server Identifier :returns: :class:`Server` """ response = self.client.get('/servers/%s' % server_id) return Server(response.json()) def create(self, server): """ Create a server :param server: A :class:`Server` to create :returns: :class:`Server` """ response = self.client.post('/servers', data=json.dumps(server)) return Server(response.json()) def update(self, server): """ Update a server :param server: A :class:`Server` to update :returns: :class:`Server` """ response = self.client.put('/servers/%s' % server.id, data=json.dumps(server.changes)) return Server(response.json()) def delete(self, server): """ Delete a server :param server: A :class:`Server`, or Server Identifier to delete """ if isinstance(server, Server): self.client.delete('/servers/%s' % server.id) else: self.client.delete('/servers/%s' % server) python-designateclient-2.11.0/designateclient/v1/sync.py0000666000175000017500000000222413366577761023343 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient import client class SyncController(client.Controller): def sync_all(self): """ Sync Everything """ self.client.post('/domains/sync') def sync_domain(self, domain_id): """ Sync Single Domain """ self.client.post('/domains/%s/sync' % domain_id) def sync_record(self, domain_id, record_id): """ Sync Single Record """ self.client.post('/domains/%s/records/%s/sync' % (domain_id, record_id)) python-designateclient-2.11.0/designateclient/v1/diagnostics.py0000666000175000017500000000167413366577761024706 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient import client class DiagnosticsController(client.Controller): def ping(self, service, host): """ Ping a service on a given host """ response = self.client.get('/diagnostics/ping/%s/%s' % (service, host)) return response.json() python-designateclient-2.11.0/designateclient/v1/records.py0000666000175000017500000000666013366577761024040 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json from designateclient import client from designateclient import utils from designateclient.v1.domains import Domain from designateclient import warlock Record = warlock.model_factory(utils.load_schema('v1', 'record')) class RecordsController(client.CrudController): def list(self, domain): """ Retrieve a list of records :param domain: :class:`Domain` or Domain Identifier :returns: A list of :class:`Record` """ domain_id = domain.id if isinstance(domain, Domain) else domain response = self.client.get('/domains/%(domain_id)s/records' % { 'domain_id': domain_id }) return [Record(i) for i in response.json()['records']] def get(self, domain, record_id): """ Retrieve a record :param domain: :class:`Domain` or Domain Identifier :param record_id: Record Identifier :returns: :class:`Record` """ domain_id = domain.id if isinstance(domain, Domain) else domain uri = '/domains/%(domain_id)s/records/%(record_id)s' % { 'domain_id': domain_id, 'record_id': record_id } response = self.client.get(uri) return Record(response.json()) def create(self, domain, record): """ Create a record :param domain: :class:`Domain` or Domain Identifier :param record: A :class:`Record` to create :returns: :class:`Record` """ domain_id = domain.id if isinstance(domain, Domain) else domain uri = '/domains/%(domain_id)s/records' % { 'domain_id': domain_id } response = self.client.post(uri, data=json.dumps(record)) return Record(response.json()) def update(self, domain, record): """ Update a record :param domain: :class:`Domain` or Domain Identifier :param record: A :class:`Record` to update :returns: :class:`Record` """ domain_id = domain.id if isinstance(domain, Domain) else domain uri = '/domains/%(domain_id)s/records/%(record_id)s' % { 'domain_id': domain_id, 'record_id': record.id } response = self.client.put(uri, data=json.dumps(record.changes)) return Record(response.json()) def delete(self, domain, record): """ Delete a record :param domain: :class:`Domain` or Domain Identifier :param record: A :class:`Record`, or Record Identifier to delete """ domain_id = domain.id if isinstance(domain, Domain) else domain record_id = record.id if isinstance(record, Record) else record uri = '/domains/%(domain_id)s/records/%(record_id)s' % { 'domain_id': domain_id, 'record_id': record_id } self.client.delete(uri) python-designateclient-2.11.0/designateclient/v1/__init__.py0000666000175000017500000001376313366577761024140 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from debtcollector import removals from stevedore import extension from designateclient import exceptions from designateclient import utils from designateclient import version @removals.removed_class( 'designateclient.v1.Client', replacement='designateclient.v2.client.Client', message='Designate v1 API is being retired, and the v1 Client class will ' 'stop functioning. Please update code to the ' 'designateclient.v2.client.Client class. The API is deprecated', version='2.2.0', removal_version='?', stacklevel=3) class Client(object): """Client for the Designate v1 API""" def __init__(self, endpoint=None, username=None, user_id=None, user_domain_id=None, user_domain_name=None, password=None, tenant_name=None, tenant_id=None, domain_name=None, domain_id=None, project_name=None, project_id=None, project_domain_name=None, project_domain_id=None, auth_url=None, token=None, endpoint_type='publicURL', region_name=None, service_type='dns', insecure=False, session=None, cacert=None, all_tenants=None, edit_managed=None, timeout=None): """ :param endpoint: Endpoint URL :param token: A token instead of username / password :param insecure: Allow "insecure" HTTPS requests """ if endpoint: endpoint = endpoint.rstrip('/') if not endpoint.endswith('v1'): endpoint = "%s/v1" % endpoint # Compatibility code to mimic the old behaviour of the client if session is None: session = utils.get_session( auth_url=auth_url, endpoint=endpoint, domain_id=domain_id, domain_name=domain_name, project_id=project_id or tenant_id, project_name=project_name or tenant_name, project_domain_name=project_domain_name, project_domain_id=project_domain_id, username=username, user_id=user_id, password=password, user_domain_id=user_domain_id, user_domain_name=user_domain_name, token=token, insecure=insecure, cacert=cacert, ) # NOTE: all_tenants and edit_managed are pulled from the session for # backwards compat reasons, do not pull additional modifiers from # here. Once removed, the kwargs above should default to False. if all_tenants is None: self.all_tenants = getattr(session, 'all_tenants', False) else: self.all_tenants = all_tenants if edit_managed is None: self.edit_managed = getattr(session, 'edit_managed', False) else: self.edit_managed = edit_managed # Since we have to behave nicely like a legacy client/bindings we use # an adapter around the session to not modify it's state. interface = endpoint_type.rstrip('URL') self.session = utils.AdapterWithTimeout( session, auth=session.auth, endpoint_override=endpoint, region_name=region_name, service_type=service_type, interface=interface, user_agent='python-designateclient-%s' % version.version_info, version='1', timeout=timeout, ) def _load_controller(ext): controller = ext.plugin(client=self) setattr(self, ext.name, controller) # Load all controllers mgr = extension.ExtensionManager('designateclient.v1.controllers') mgr.map(_load_controller) def wrap_api_call(self, func, *args, **kw): """ Wrap a self. with exception handling :param func: The function to wrap """ kw['raise_exc'] = False kw.setdefault('headers', {}) kw['headers'].setdefault('Content-Type', 'application/json') if self.all_tenants: kw['headers'].update({'X-Auth-All-Projects': 'true'}) if self.edit_managed: kw['headers'].update({'X-Designate-Edit-Managed-Records': 'true'}) # Trigger the request response = func(*args, **kw) # Decode is response, if possible try: response_payload = response.json() except ValueError: response_payload = {} if response.status_code == 400: raise exceptions.BadRequest(**response_payload) elif response.status_code in (401, 403, 413): raise exceptions.Forbidden(**response_payload) elif response.status_code == 404: raise exceptions.NotFound(**response_payload) elif response.status_code == 409: raise exceptions.Conflict(**response_payload) elif response.status_code >= 500: raise exceptions.Unknown(**response_payload) else: return response def get(self, path, **kw): return self.wrap_api_call(self.session.get, path, **kw) def post(self, path, **kw): return self.wrap_api_call(self.session.post, path, **kw) def put(self, path, **kw): return self.wrap_api_call(self.session.put, path, **kw) def delete(self, path, **kw): return self.wrap_api_call(self.session.delete, path, **kw) python-designateclient-2.11.0/designateclient/v1/touch.py0000666000175000017500000000155113366577761023513 0ustar zuulzuul00000000000000# Copyright 2013 Hewlett-Packard Development Company, L.P. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient import client class TouchController(client.Controller): def domain(self, domain_id): """ Touch a single Domain """ self.client.post('/domains/%s/touch' % domain_id) python-designateclient-2.11.0/designateclient/v1/domains.py0000666000175000017500000000522113366577761024021 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json from designateclient import client from designateclient import utils from designateclient import warlock Domain = warlock.model_factory(utils.load_schema('v1', 'domain')) Server = warlock.model_factory(utils.load_schema('v1', 'server')) class DomainsController(client.CrudController): def list(self): """ Retrieve a list of domains :returns: A list of :class:`Domain` """ response = self.client.get('/domains') return [Domain(i) for i in response.json()['domains']] def get(self, domain_id): """ Retrieve a domain :param domain_id: Domain Identifier :returns: :class:`Domain` """ response = self.client.get('/domains/%s' % domain_id) return Domain(response.json()) def create(self, domain): """ Create a domain :param domain: A :class:`Domain` to create :returns: :class:`Domain` """ response = self.client.post('/domains', data=json.dumps(domain)) return Domain(response.json()) def update(self, domain): """ Update a domain :param domain: A :class:`Domain` to update :returns: :class:`Domain` """ response = self.client.put('/domains/%s' % domain.id, data=json.dumps(domain.changes)) return Domain(response.json()) def delete(self, domain): """ Delete a domain :param domain: A :class:`Domain`, or Domain Identifier to delete """ if isinstance(domain, Domain): self.client.delete('/domains/%s' % domain.id) else: self.client.delete('/domains/%s' % domain) def list_domain_servers(self, domain_id): """ Retrieve the list of nameservers for a domain :param domain_id: Domain Identifier :returns: A list of :class:`Server` """ response = self.client.get('/domains/%s/servers' % domain_id) return [Server(i) for i in response.json()['servers']] python-designateclient-2.11.0/designateclient/v1/reports.py0000666000175000017500000000357513366577761024077 0ustar zuulzuul00000000000000# Copyright 2013 Hewlett-Packard Development Company, L.P. All Rights Reserved. # # Author: Patrick Galbraith # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient import client class ReportsController(client.Controller): def count_all(self): """ Domain, Records and tenant total count """ response = self.client.get('/reports/counts') return response.json() def count_domains(self): """ Domain total count """ response = self.client.get('/reports/counts/domains') return response.json() def count_tenants(self): """ Tenant total count """ response = self.client.get('/reports/counts/tenants') return response.json() def count_records(self): """ Record total count """ response = self.client.get('/reports/counts/records') return response.json() def tenants_all(self): """ Per tenant count """ response = self.client.get('/reports/tenants') return response.json()['tenants'] def tenant_domains(self, other_tenant_id): """ Tenant's domain count """ response = self.client.get('/reports/tenants/%s' % other_tenant_id) return [{'domain': d} for d in response.json()['domains']] python-designateclient-2.11.0/designateclient/v1/quotas.py0000666000175000017500000000234213366577761023704 0ustar zuulzuul00000000000000# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json from designateclient import client class QuotasController(client.Controller): def get(self, tenant_id): """ Ping a service on a given host """ response = self.client.get('/quotas/%s' % tenant_id) return response.json() def update(self, tenant_id, values): response = self.client.put('/quotas/%s' % tenant_id, data=json.dumps(values)) return response.json() def reset(self, tenant_id): response = self.client.delete('/quotas/%s' % tenant_id) return response python-designateclient-2.11.0/designateclient/__init__.py0000666000175000017500000000130713366577761023601 0ustar zuulzuul00000000000000# Copyright 2017 Huawei, Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # from designateclient import version __version__ = version.version_info.version_string() python-designateclient-2.11.0/designateclient/warlock.py0000666000175000017500000000756413366577761023517 0ustar zuulzuul00000000000000# Copyright 2012 Brian Waldon # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # # Code copied from Warlock, as warlock depends on jsonschema==0.2 # Hopefully we can upstream the changes ASAP. # import copy import logging import jsonschema import six LOG = logging.getLogger(__name__) class InvalidOperation(RuntimeError): pass class ValidationError(ValueError): pass def model_factory(schema): """Generate a model class based on the provided JSON Schema :param schema: dict representing valid JSON schema """ schema = copy.deepcopy(schema) def validator(obj): """Apply a JSON schema to an object""" try: jsonschema.validate(obj, schema, cls=jsonschema.Draft3Validator) except jsonschema.ValidationError as e: raise ValidationError(str(e)) class Model(dict): """Self-validating model for arbitrary objects""" def __init__(self, *args, **kwargs): d = dict(*args, **kwargs) # we overload setattr so set this manually self.__dict__['validator'] = validator try: self.validator(d) except ValidationError as e: raise ValueError('Validation Error: %s' % str(e)) else: dict.__init__(self, d) self.__dict__['changes'] = {} def __getattr__(self, key): try: return self.__getitem__(key) except KeyError: raise AttributeError(key) def __setitem__(self, key, value): mutation = dict(self.items()) mutation[key] = value try: self.validator(mutation) except ValidationError as e: raise InvalidOperation(str(e)) dict.__setitem__(self, key, value) self.__dict__['changes'][key] = value def __setattr__(self, key, value): self.__setitem__(key, value) def clear(self): raise InvalidOperation() def pop(self, key, default=None): raise InvalidOperation() def popitem(self): raise InvalidOperation() def __delitem__(self, key): raise InvalidOperation() # NOTE(termie): This is kind of the opposite of what copy usually does def copy(self): return copy.deepcopy(dict(self)) def update(self, other): # NOTE(kiall): It seems update() doesn't update the # self.__dict__['changes'] dict correctly. mutation = dict(self.items()) mutation.update(other) try: self.validator(mutation) except ValidationError as e: raise InvalidOperation(str(e)) dict.update(self, other) def iteritems(self): return six.iteritems(copy.deepcopy(dict(self))) def items(self): return list(six.iteritems(copy.deepcopy(dict(self)))) def itervalues(self): return six.itervalues(copy.deepcopy(dict(self))) def keys(self): return list(six.iterkeys(copy.deepcopy(dict(self)))) def values(self): return list(six.itervalues(copy.deepcopy(dict(self)))) @property def changes(self): return copy.deepcopy(self.__dict__['changes']) Model.__name__ = str(schema['title']) return Model python-designateclient-2.11.0/designateclient/cli/0000775000175000017500000000000013366600247022216 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/cli/servers.py0000666000175000017500000000516013366577761024303 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from designateclient.cli import base from designateclient.v1.servers import Server LOG = logging.getLogger(__name__) class ListServersCommand(base.ListCommand): """List Servers""" columns = ['id', 'name'] def execute(self, parsed_args): return self.client.servers.list() class GetServerCommand(base.GetCommand): """Get Server""" def get_parser(self, prog_name): parser = super(GetServerCommand, self).get_parser(prog_name) parser.add_argument('id', help="Server ID.") return parser def execute(self, parsed_args): return self.client.servers.get(parsed_args.id) class CreateServerCommand(base.CreateCommand): """Create Server""" def get_parser(self, prog_name): parser = super(CreateServerCommand, self).get_parser(prog_name) parser.add_argument('--name', help="Server name.", required=True) return parser def execute(self, parsed_args): server = Server( name=parsed_args.name, ) return self.client.servers.create(server) class UpdateServerCommand(base.UpdateCommand): """Update Server""" def get_parser(self, prog_name): parser = super(UpdateServerCommand, self).get_parser(prog_name) parser.add_argument('id', help="Server ID.") parser.add_argument('--name', help="Server name.") return parser def execute(self, parsed_args): # TODO(kiall): API needs updating.. this get is silly server = self.client.servers.get(parsed_args.id) if parsed_args.name: server.name = parsed_args.name return self.client.servers.update(server) class DeleteServerCommand(base.DeleteCommand): """Delete Server""" def get_parser(self, prog_name): parser = super(DeleteServerCommand, self).get_parser(prog_name) parser.add_argument('id', help="Server ID.") return parser def execute(self, parsed_args): return self.client.servers.delete(parsed_args.id) python-designateclient-2.11.0/designateclient/cli/sync.py0000666000175000017500000000353413366577761023571 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from designateclient.cli import base LOG = logging.getLogger(__name__) class SyncAllCommand(base.DeleteCommand): """Sync Everything""" def execute(self, parsed_args): self.client.sync.sync_all() LOG.info('Synchronization of all domains scheduled') class SyncDomainCommand(base.DeleteCommand): """Sync a single Domain""" def get_parser(self, prog_name): parser = super(SyncDomainCommand, self).get_parser(prog_name) parser.add_argument('domain_id', help="Domain ID") return parser def execute(self, parsed_args): self.client.sync.sync_domain(parsed_args.domain_id) LOG.info('Synchronization of domain scheduled') class SyncRecordCommand(base.DeleteCommand): """Sync a single Record""" def get_parser(self, prog_name): parser = super(SyncRecordCommand, self).get_parser(prog_name) parser.add_argument('domain_id', help="Domain ID") parser.add_argument('record_id', help="Record ID") return parser def execute(self, parsed_args): self.client.sync.sync_record(parsed_args.domain_id, parsed_args.record_id) LOG.info('Synchronization of record scheduled') python-designateclient-2.11.0/designateclient/cli/diagnostics.py0000666000175000017500000000237213366577761025123 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from designateclient.cli import base LOG = logging.getLogger(__name__) class PingCommand(base.GetCommand): """Ping a service on a given host""" def get_parser(self, prog_name): parser = super(PingCommand, self).get_parser(prog_name) parser.add_argument('--service', help="Service name (e.g. central)", required=True) parser.add_argument('--host', help="Hostname", required=True) return parser def execute(self, parsed_args): return self.client.diagnostics.ping(parsed_args.service, parsed_args.host) python-designateclient-2.11.0/designateclient/cli/records.py0000666000175000017500000001470513366577761024260 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from designateclient.cli import base from designateclient.v1.records import Record LOG = logging.getLogger(__name__) class ListRecordsCommand(base.ListCommand): """List Records""" columns = ['id', 'type', 'name', 'data'] def get_parser(self, prog_name): parser = super(ListRecordsCommand, self).get_parser(prog_name) parser.add_argument('domain_id', help="Domain ID or name.") return parser def execute(self, parsed_args): domain_id = self.find_resourceid_by_name_or_id( 'domains', parsed_args.domain_id) return self.client.records.list(domain_id) class GetRecordCommand(base.GetCommand): """Get Record""" def get_parser(self, prog_name): parser = super(GetRecordCommand, self).get_parser(prog_name) parser.add_argument('domain_id', help="Domain ID or name.") parser.add_argument('id', help="Record ID.") return parser def execute(self, parsed_args): domain_id = self.find_resourceid_by_name_or_id( 'domains', parsed_args.domain_id) return self.client.records.get(domain_id, parsed_args.id) class CreateRecordCommand(base.CreateCommand): """Create Record""" def get_parser(self, prog_name): parser = super(CreateRecordCommand, self).get_parser(prog_name) parser.add_argument('domain_id', help="Domain ID or name.") parser.add_argument( '--name', help="Record (relative|absolute) name.", required=True) parser.add_argument('--type', help="Record type.", required=True) parser.add_argument('--data', help="Record data.", required=True) parser.add_argument('--ttl', type=int, help="Record TTL.") parser.add_argument('--priority', type=int, help="Record priority.") parser.add_argument('--description', help="Description.") return parser def execute(self, parsed_args): domain_id = self.find_resourceid_by_name_or_id( 'domains', parsed_args.domain_id) if not parsed_args.name.endswith('.'): # Relative name? domain_name = self.client.domains.get(domain_id)['name'] absolute = parsed_args.name + '.' relative = absolute + domain_name if absolute.endswith('.' + domain_name): # Relative name or absolute name missing final period? msg = ('"%s" is a relative name but looks like an absolute ' 'name, use --name "%s" or "%s"' % (parsed_args.name, absolute, relative)) raise ValueError(msg) parsed_args.name = relative record = Record( name=parsed_args.name, type=parsed_args.type, data=parsed_args.data, ) if parsed_args.ttl is not None: record.ttl = parsed_args.ttl if parsed_args.priority is not None: record.priority = parsed_args.priority if parsed_args.description: record.description = parsed_args.description return self.client.records.create(domain_id, record) class UpdateRecordCommand(base.UpdateCommand): """Update Record""" def get_parser(self, prog_name): parser = super(UpdateRecordCommand, self).get_parser(prog_name) parser.add_argument('domain_id', help="Domain ID or name.") parser.add_argument('id', help="Record ID.") parser.add_argument('--name', help="Record name.") parser.add_argument('--type', help="Record type.") parser.add_argument('--data', help="Record data.") description_group = parser.add_mutually_exclusive_group() description_group.add_argument('--description', help="Description.") description_group.add_argument('--no-description', action='store_true') ttl_group = parser.add_mutually_exclusive_group() ttl_group.add_argument('--ttl', type=int, help="Record time to live (seconds).") ttl_group.add_argument('--no-ttl', action='store_true') priotity_group = parser.add_mutually_exclusive_group() priotity_group.add_argument('--priority', type=int, help="Record priority.") priotity_group.add_argument('--no-priority', action='store_true') return parser def execute(self, parsed_args): # TODO(kiall): API needs updating.. this get is silly record = self.client.records.get(parsed_args.domain_id, parsed_args.id) if parsed_args.name: record.name = parsed_args.name if parsed_args.type: record.type = parsed_args.type if parsed_args.data: record.data = parsed_args.data if parsed_args.no_ttl: record.ttl = None elif parsed_args.ttl is not None: record.ttl = parsed_args.ttl if parsed_args.no_priority: record.priority = None elif parsed_args.priority is not None: record.priority = parsed_args.priority if parsed_args.no_description: record.description = None elif parsed_args.description: record.description = parsed_args.description domain_id = self.find_resourceid_by_name_or_id( 'domains', parsed_args.domain_id) return self.client.records.update(domain_id, record) class DeleteRecordCommand(base.DeleteCommand): """Delete Record""" def get_parser(self, prog_name): parser = super(DeleteRecordCommand, self).get_parser(prog_name) parser.add_argument('domain_id', help="Domain ID or name.") parser.add_argument('id', help="Record ID.") return parser def execute(self, parsed_args): domain_id = self.find_resourceid_by_name_or_id( 'domains', parsed_args.domain_id) return self.client.records.delete(domain_id, parsed_args.id) python-designateclient-2.11.0/designateclient/cli/__init__.py0000666000175000017500000000000013366577761024335 0ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/cli/touch.py0000666000175000017500000000215113366577761023731 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from designateclient.cli import base LOG = logging.getLogger(__name__) class TouchDomainCommand(base.DeleteCommand): """Touch a single Domain""" def get_parser(self, prog_name): parser = super(TouchDomainCommand, self).get_parser(prog_name) parser.add_argument('domain_id', help="Domain ID") return parser def execute(self, parsed_args): self.client.touch.domain(parsed_args.domain_id) LOG.info('Domain touched successfully') python-designateclient-2.11.0/designateclient/cli/domains.py0000666000175000017500000001062413366577761024245 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from designateclient.cli import base from designateclient.v1.domains import Domain LOG = logging.getLogger(__name__) class ListDomainsCommand(base.ListCommand): """List Domains""" columns = ['id', 'name', 'serial'] def execute(self, parsed_args): return self.client.domains.list() class GetDomainCommand(base.GetCommand): """Get Domain""" def get_parser(self, prog_name): parser = super(GetDomainCommand, self).get_parser(prog_name) parser.add_argument('id', help="Domain ID or name.") return parser def execute(self, parsed_args): id = self.find_resourceid_by_name_or_id('domains', parsed_args.id) return self.client.domains.get(id) class CreateDomainCommand(base.CreateCommand): """Create Domain""" def get_parser(self, prog_name): parser = super(CreateDomainCommand, self).get_parser(prog_name) parser.add_argument('--name', help="Domain name.", required=True) parser.add_argument('--email', help="Domain email.", required=True) parser.add_argument('--ttl', type=int, help="Time to live (seconds).") parser.add_argument('--description', help="Description.") return parser def execute(self, parsed_args): domain = Domain( name=parsed_args.name, email=parsed_args.email, ) if parsed_args.description: domain.description = parsed_args.description if parsed_args.ttl is not None: domain.ttl = parsed_args.ttl return self.client.domains.create(domain) class UpdateDomainCommand(base.UpdateCommand): """Update Domain""" def get_parser(self, prog_name): parser = super(UpdateDomainCommand, self).get_parser(prog_name) parser.add_argument('id', help="Domain ID or name.") parser.add_argument('--name', help="Domain name.") parser.add_argument('--email', help="Domain email.") parser.add_argument('--ttl', type=int, help="Time to live (seconds).") description_group = parser.add_mutually_exclusive_group() description_group.add_argument('--description', help="Description.") description_group.add_argument('--no-description', action='store_true') return parser def execute(self, parsed_args): # TODO(kiall): API needs updating.. this get is silly id = self.find_resourceid_by_name_or_id('domains', parsed_args.id) domain = self.client.domains.get(id) if parsed_args.name: domain.name = parsed_args.name if parsed_args.email: domain.email = parsed_args.email if parsed_args.ttl is not None: domain.ttl = parsed_args.ttl if parsed_args.no_description: domain.description = None elif parsed_args.description: domain.description = parsed_args.description return self.client.domains.update(domain) class DeleteDomainCommand(base.DeleteCommand): """Delete Domain""" def get_parser(self, prog_name): parser = super(DeleteDomainCommand, self).get_parser(prog_name) parser.add_argument('id', help="Domain ID or name.") return parser def execute(self, parsed_args): id = self.find_resourceid_by_name_or_id('domains', parsed_args.id) return self.client.domains.delete(id) class ListDomainServersCommand(base.ListCommand): """List Domain Servers""" columns = ['name'] def get_parser(self, prog_name): parser = super(ListDomainServersCommand, self).get_parser(prog_name) parser.add_argument('id', help="Domain ID or name.") return parser def execute(self, parsed_args): id = self.find_resourceid_by_name_or_id('domains', parsed_args.id) return self.client.domains.list_domain_servers(id) python-designateclient-2.11.0/designateclient/cli/base.py0000666000175000017500000001173313366577761023527 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import abc import warnings from keystoneauth1 import exceptions as ks_exceptions from osc_lib.command import command import six from designateclient import exceptions from designateclient import utils from designateclient.v1 import Client @six.add_metaclass(abc.ABCMeta) class Command(command.Command): def run(self, parsed_args): warnings.simplefilter('once', category=DeprecationWarning) warnings.warn( 'The "designate" CLI is being deprecated in favour of the ' '"openstack" CLI plugin. All designate API v2 commands are ' 'implemented there. When the v1 API is removed this CLI will ' 'stop functioning', DeprecationWarning) warnings.resetwarnings() warnings.simplefilter('ignore', category=DeprecationWarning) self.client = Client( region_name=self.app.options.os_region_name, service_type=self.app.options.os_service_type, endpoint_type=self.app.options.os_endpoint_type, session=self.app.session, all_tenants=self.app.options.all_tenants, edit_managed=self.app.options.edit_managed, endpoint=self.app.options.os_endpoint) warnings.resetwarnings() try: return super(Command, self).run(parsed_args) except exceptions.RemoteError as e: columns = ['Code', 'Type'] values = [e.code, e.type] if e.message: columns.append('Message') values.append(e.message) if e.errors: columns.append('Errors') values.append(e.errors) self.error_output(parsed_args, columns, values) except ks_exceptions.EndpointNotFound as e: self.app.log.error('No endpoint was found. You must provide a ' 'username or user id via --os-username, ' '--os-user-id, env[OS_USERNAME] or ' 'env[OS_USER_ID]. You may also be using a ' 'cloud that does not have the V1 API enabled. ' 'If your cloud does not have the V1 DNS API ' 'use the openstack CLI to interact with the ' 'DNS Service.') return 1 def error_output(self, parsed_args, column_names, data): self.formatter.emit_one(column_names, data, self.app.stdout, parsed_args) self.app.log.error('The requested action did not complete ' 'successfully') @abc.abstractmethod def execute(self, parsed_args): """ Execute something, this is since we overload self.take_action() in order to format the data This method __NEEDS__ to be overloaded! :param parsed_args: The parsed args that are given by take_action() """ def post_execute(self, data): """ Format the results locally if needed, by default we just return data :param data: Whatever is returned by self.execute() """ return data def take_action(self, parsed_args): results = self.execute(parsed_args) return self.post_execute(results) def find_resourceid_by_name_or_id(self, resource_plural, name_or_id): resource_client = getattr(self.client, resource_plural) return utils.find_resourceid_by_name_or_id(resource_client, name_or_id) class ListCommand(Command, command.Lister): columns = None def post_execute(self, results): if len(results) > 0: columns = self.columns or utils.get_columns(results) data = [utils.get_item_properties(i, columns) for i in results] return columns, data else: return [], () class GetCommand(Command, command.ShowOne): def post_execute(self, results): return results.keys(), results.values() class CreateCommand(Command, command.ShowOne): def post_execute(self, results): return results.keys(), results.values() class UpdateCommand(Command, command.ShowOne): def post_execute(self, results): return results.keys(), results.values() class DeleteCommand(Command, command.ShowOne): def post_execute(self, results): return [], [] python-designateclient-2.11.0/designateclient/cli/reports.py0000666000175000017500000000415713366577761024315 0ustar zuulzuul00000000000000# Copyright 2013 Hewlett-Packard Development Company, L.P. All Rights Reserved. # # Author: Patrick Galbraith # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.cli import base class DomainCountCommand(base.GetCommand): """Get counts for total domains""" def execute(self, parsed_args): return self.client.reports.count_domains() class RecordCountCommand(base.GetCommand): """Get counts for total records""" def execute(self, parsed_args): return self.client.reports.count_records() class TenantCountCommand(base.GetCommand): """Get counts for total tenants""" def execute(self, parsed_args): return self.client.reports.count_tenants() class CountsCommand(base.GetCommand): """Get count totals for all tenants, domains and records""" def execute(self, parsed_args): return self.client.reports.count_all() class TenantsCommand(base.ListCommand): """Get list of tenants and domain count for each""" columns = ['domain_count', 'id'] def execute(self, parsed_args): return self.client.reports.tenants_all() class TenantCommand(base.ListCommand): """Get a list of domains for given tenant""" columns = ['domain'] def get_parser(self, prog_name): parser = super(TenantCommand, self).get_parser(prog_name) parser.add_argument('--report-tenant-id', help="The tenant_id being reported on.", required=True) return parser def execute(self, parsed_args): return self.client.reports.tenant_domains(parsed_args.report_tenant_id) python-designateclient-2.11.0/designateclient/cli/quotas.py0000666000175000017500000000534113366577761024127 0ustar zuulzuul00000000000000# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from designateclient.cli import base LOG = logging.getLogger(__name__) class GetQuotaCommand(base.GetCommand): """Get Quota""" def get_parser(self, prog_name): parser = super(GetQuotaCommand, self).get_parser(prog_name) parser.add_argument('tenant_id', help="Tenant ID") return parser def execute(self, parsed_args): return self.client.quotas.get(parsed_args.tenant_id) class UpdateQuotaCommand(base.UpdateCommand): """Update Quota""" def get_parser(self, prog_name): parser = super(UpdateQuotaCommand, self).get_parser(prog_name) parser.add_argument('tenant_id', help="Tenant ID.") parser.add_argument('--domains', help="Allowed domains.", type=int) parser.add_argument('--domain-recordsets', help="Allowed domain records.", type=int) parser.add_argument('--recordset-records', help="Allowed recordset records.", type=int) parser.add_argument('--domain-records', help="Allowed domain records.", type=int) parser.add_argument('--api-export-size', help="Allowed zone export recordsets.", type=int) return parser def execute(self, parsed_args): # TODO(kiall): API needs updating.. this get is silly quota = self.client.quotas.get(parsed_args.tenant_id) for key, old in quota.items(): new = getattr(parsed_args, key) if new is not None and new != old: quota[key] = new return self.client.quotas.update(parsed_args.tenant_id, quota) class ResetQuotaCommand(base.DeleteCommand): """Reset Quota""" def get_parser(self, prog_name): parser = super(ResetQuotaCommand, self).get_parser(prog_name) parser.add_argument('tenant_id', help="Tenant ID.") return parser def execute(self, parsed_args): self.client.quotas.reset(parsed_args.tenant_id) python-designateclient-2.11.0/designateclient/version.py0000666000175000017500000000130713366577761023527 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import pbr.version version_info = pbr.version.VersionInfo('python-designateclient') python-designateclient-2.11.0/designateclient/shell.py0000666000175000017500000002447213366577761023161 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging import os import traceback from cliff.app import App from cliff.commandmanager import CommandManager from designateclient import utils from designateclient.version import version_info as version def env(*vars, **kwargs): """Search for the first defined of possibly many env vars Returns the first environment variable defined in vars, or returns the default defined in kwargs. """ for v in vars: value = os.environ.get(v) if value: return value return kwargs.get('default', '') class DesignateShell(App): CONSOLE_MESSAGE_FORMAT = '%(levelname)s: %(message)s' DEFAULT_VERBOSE_LEVEL = 0 def __init__(self): super(DesignateShell, self).__init__( description='Designate Client', version=version.version_string(), command_manager=CommandManager('designateclient.cli'), ) self.log = logging.getLogger(__name__) def build_option_parser(self, description, version): parser = super(DesignateShell, self).build_option_parser( description, version) parser.add_argument('--os-username', default=env('OS_USERNAME'), help='Name used for authentication with the ' 'OpenStack Identity service. ' 'Defaults to env[OS_USERNAME].') parser.add_argument('--os-user-id', default=env('OS_USER_ID'), help='User ID used for authentication with the ' 'OpenStack Identity service. ' 'Defaults to env[OS_USER_ID].') parser.add_argument('--os-user-domain-id', default=env('OS_USER_DOMAIN_ID'), help='Defaults to env[OS_USER_DOMAIN_ID].') parser.add_argument('--os-user-domain-name', default=env('OS_USER_DOMAIN_NAME'), help='Defaults to env[OS_USER_DOMAIN_NAME].') parser.add_argument('--os-password', default=env('OS_PASSWORD'), help='Password used for authentication with the ' 'OpenStack Identity service. ' 'Defaults to env[OS_PASSWORD].') parser.add_argument('--os-tenant-name', default=env('OS_TENANT_NAME'), help='Tenant to request authorization on. ' 'Defaults to env[OS_TENANT_NAME].') parser.add_argument('--os-tenant-id', default=env('OS_TENANT_ID'), help='Tenant to request authorization on. ' 'Defaults to env[OS_TENANT_ID].') parser.add_argument('--os-project-name', default=env('OS_PROJECT_NAME'), help='Project to request authorization on. ' 'Defaults to env[OS_PROJECT_NAME].') parser.add_argument('--os-domain-name', default=env('OS_DOMAIN_NAME'), help='Project to request authorization on. ' 'Defaults to env[OS_DOMAIN_NAME].') parser.add_argument('--os-domain-id', default=env('OS_DOMAIN_ID'), help='Defaults to env[OS_DOMAIN_ID].') parser.add_argument('--os-project-id', default=env('OS_PROJECT_ID'), help='Project to request authorization on. ' 'Defaults to env[OS_PROJECT_ID].') parser.add_argument('--os-project-domain-id', default=env('OS_PROJECT_DOMAIN_ID'), help='Defaults to env[OS_PROJECT_DOMAIN_ID].') parser.add_argument('--os-project-domain-name', default=env('OS_PROJECT_DOMAIN_NAME'), help='Defaults to env[OS_PROJECT_DOMAIN_NAME].') parser.add_argument('--os-auth-url', default=env('OS_AUTH_URL'), help='Specify the Identity endpoint to use for ' 'authentication. ' 'Defaults to env[OS_AUTH_URL].') parser.add_argument('--os-region-name', default=env('OS_REGION_NAME'), help='Specify the region to use. ' 'Defaults to env[OS_REGION_NAME].') parser.add_argument('--os-token', default=env('OS_SERVICE_TOKEN'), help='Specify an existing token to use instead of ' 'retrieving one via authentication (e.g. ' 'with username & password). ' 'Defaults to env[OS_SERVICE_TOKEN].') parser.add_argument('--os-endpoint', default=env('OS_DNS_ENDPOINT', 'OS_SERVICE_ENDPOINT'), help='Specify an endpoint to use instead of ' 'retrieving one from the service catalog ' '(via authentication). ' 'Defaults to env[OS_DNS_ENDPOINT].') parser.add_argument('--os-endpoint-type', default=env('OS_ENDPOINT_TYPE', default='publicURL'), help='Defaults to env[OS_ENDPOINT_TYPE].') parser.add_argument('--os-service-type', default=env('OS_DNS_SERVICE_TYPE', default='dns'), help=("Defaults to env[OS_DNS_SERVICE_TYPE], or " "'dns'.")) parser.add_argument('--os-cacert', default=env('OS_CACERT'), help=('CA certificate bundle file. Defaults to ' 'env[OS_CACERT].')) parser.add_argument('--insecure', action='store_true', help="Explicitly allow 'insecure' SSL requests.") parser.add_argument('--all-tenants', action='store_true', help="Allows to list all domains from all " "tenants.") parser.add_argument('--edit-managed', action='store_true', help='Allows to edit records that are marked as ' 'managed.') return parser def configure_logging(self): """Configure logging for the app Cliff sets some defaults we don't want so re-work it a bit """ if self.options.debug: # --debug forces verbose_level 3 # Set this here so cliff.app.configure_logging() can work self.options.verbose_level = 3 super(DesignateShell, self).configure_logging() root_logger = logging.getLogger('') # Requests logs some stuff at INFO that we don't want # unless we have DEBUG requests_log = logging.getLogger("requests") requests_log.setLevel(logging.ERROR) # Other modules we don't want DEBUG output for so # don't reset them below iso8601_log = logging.getLogger("iso8601") iso8601_log.setLevel(logging.ERROR) # Set logging to the requested level self.dump_stack_trace = False if self.options.verbose_level == 0: # --quiet root_logger.setLevel(logging.ERROR) elif self.options.verbose_level == 1: # This is the default case, no --debug, --verbose or --quiet root_logger.setLevel(logging.WARNING) elif self.options.verbose_level == 2: # One --verbose root_logger.setLevel(logging.INFO) elif self.options.verbose_level >= 3: # Two or more --verbose root_logger.setLevel(logging.DEBUG) requests_log.setLevel(logging.DEBUG) if self.options.debug: # --debug forces traceback self.dump_stack_trace = True def initialize_app(self, argv): super(DesignateShell, self).initialize_app(argv) self.session = utils.get_session( auth_url=self.options.os_auth_url, endpoint=self.options.os_endpoint, domain_id=self.options.os_domain_id, domain_name=self.options.os_domain_name, project_id=self.options.os_project_id or self.options.os_tenant_id, project_name=(self.options.os_project_name or self.options.os_tenant_name), project_domain_name=self.options.os_project_domain_name, project_domain_id=self.options.os_project_domain_id, username=self.options.os_username, user_id=self.options.os_user_id, password=self.options.os_password, user_domain_id=self.options.os_user_domain_id, user_domain_name=self.options.os_user_domain_name, token=self.options.os_token, insecure=self.options.insecure, cacert=self.options.os_cacert ) def run(self, argv): try: return super(DesignateShell, self).run(argv) except Exception as e: if not logging.getLogger('').handlers: logging.basicConfig() if self.dump_stack_trace: self.log.error(traceback.format_exc(e)) else: self.log.error('Exception raised: ' + str(e)) return 1 python-designateclient-2.11.0/designateclient/resources/0000775000175000017500000000000013366600247023461 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/resources/schemas/0000775000175000017500000000000013366600247025104 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/resources/schemas/v1/0000775000175000017500000000000013366600247025432 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/resources/schemas/v1/domain.json0000666000175000017500000000405513366577761027620 0ustar zuulzuul00000000000000{ "id": "domain", "$schema": "http://json-schema.org/draft-03/hyper-schema", "title": "domain", "description": "Domain", "additionalProperties": false, "properties": { "id": { "type": "string", "description": "Domain Identifier", "pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$", "readonly": true }, "name": { "type": "string", "description": "Domain name", "format": "domain-name", "maxLength": 255, "required": true, "readonly": true }, "email": { "type": "string", "description": "Hostmaster email address", "format": "email", "maxLength": 255, "required": true }, "ttl": { "type": "integer", "description": "Time to live", "minimum": 1, "maximum": 2147483647 }, "serial": { "type": "integer", "description": "Serial Number", "minimum": 1, "maximum": 4294967295, "readonly": true }, "description": { "type": ["string", "null"], "description": "Description for the Domain", "maxLength": 160 }, "created_at": { "type": "string", "description": "Date and time of domain creation", "format": "date-time", "readonly": true }, "updated_at": { "type": ["string", "null"], "description": "Date and time of last domain update", "format": "date-time", "readonly": true } }, "links": [{ "rel": "self", "href": "/domains/{id}" }, { "rel": "records", "href": "/domains/{id}/records" }, { "rel": "servers", "href": "/domains/{id}/servers" }, { "rel": "collection", "href": "/domains" }] } python-designateclient-2.11.0/designateclient/resources/schemas/v1/record.json0000666000175000017500000001510513366577761027625 0ustar zuulzuul00000000000000{ "id": "record", "$schema": "http://json-schema.org/draft-03/hyper-schema", "title": "record", "description": "Record", "additionalProperties": false, "properties": { "id": { "type": "string", "description": "Record Identifier", "pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$", "readonly": true }, "domain_id": { "type": "string", "description": "Domain Identifier", "pattern": "^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$", "readonly": true }, "name": { "type": "string", "description": "DNS Record Name", "format": "host-name", "maxLength": 255, "required": true }, "type": { "type": "string", "description": "DNS Record Type", "enum": ["A", "AAAA", "CNAME", "MX", "SRV", "TXT", "SPF", "NS", "PTR", "SSHFP", "SOA"], "required": true }, "data": { "type": "string", "description": "DNS Record Value", "maxLength": 255, "required": true }, "priority": { "type": ["integer", "null"], "description": "DNS Record Priority", "minimum": 0, "maximum": 65535 }, "ttl": { "type": ["integer", "null"], "description": "Time to live", "minimum": 1, "maximum": 2147483647 }, "description": { "type": ["string", "null"], "description": "Description for the record", "maxLength": 160 }, "created_at": { "type": "string", "description": "Date and time of record creation", "format": "date-time", "readonly": true }, "updated_at": { "type": ["string", "null"], "description": "Date and time of last record update", "format": "date-time", "readonly": true } }, "oneOf": [{ "description": "An A Record", "properties": { "type": { "type": "string", "enum": ["A"] }, "data": { "format": "ip-address", "required": true }, "priority": { "type": "null" } } }, { "description": "An AAAA Record", "properties": { "type": { "type": "string", "enum": ["AAAA"] }, "data": { "format": "ipv6", "required": true }, "priority": { "type": "null" } } }, { "description": "A CNAME Record", "properties": { "type": { "type": "string", "enum": ["CNAME"] }, "data": { "format": "host-name", "required": true }, "priority": { "type": "null" } } }, { "description": "A MX Record", "properties": { "type": { "type": "string", "enum": ["MX"] }, "data": { "format": "host-name", "required": true }, "priority": { "type": "integer", "required": true } } }, { "description": "A SRV Record", "properties": { "type": { "type": "string", "enum": ["SRV"] }, "name": { "type": "string", "pattern": "^(?:_[A-Za-z0-9_\\-]{1,62}\\.){2}" }, "data": { "type": "string", "pattern": "^(?:(?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])\\s){2}(?!.{255,})((?!\\-)[A-Za-z0-9_\\-]{1,63}(? # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. class Base(Exception): def __init__(self, message=None): if not message: message = self.__class__.__name__ super(Base, self).__init__(message) class UnsupportedVersion(Base): pass class ResourceNotFound(Base): pass class NoUniqueMatch(Base): pass class RemoteError(Base): def __init__(self, message=None, code=None, type=None, errors=None, request_id=None, **ignore): err_message = self._get_error_message(message, type, errors) self.message = err_message self.code = code self.type = type self.errors = errors self.request_id = request_id super(RemoteError, self).__init__(err_message) def _get_error_message(self, _message, _type, _errors): # Try to get a useful error msg if 'message' has nothing if not _message: if _errors and 'errors' in _errors: err_msg = list() for err in _errors['errors']: if 'message' in err: err_msg.append(err['message']) _message = '. '.join(err_msg) elif _type: _message = str(_type) return _message class Unknown(RemoteError): pass class BadRequest(RemoteError): pass class Forbidden(RemoteError): pass class Conflict(RemoteError): pass class NotFound(RemoteError): pass class OverQuota(RemoteError): pass python-designateclient-2.11.0/designateclient/utils.py0000666000175000017500000001442313366577761023205 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json import os import uuid from debtcollector import removals from keystoneauth1 import adapter from keystoneauth1.identity import generic from keystoneauth1 import session as ks_session from keystoneauth1 import token_endpoint import pkg_resources import six from designateclient import exceptions def resource_string(*args, **kwargs): if len(args) == 0: raise ValueError() package = kwargs.pop('package', None) if not package: package = 'designateclient' resource_path = os.path.join('resources', *args) if not pkg_resources.resource_exists(package, resource_path): raise exceptions.ResourceNotFound('Could not find the requested ' 'resource: %s' % resource_path) return pkg_resources.resource_string(package, resource_path) def load_schema(version, name, package=None): schema_string = resource_string('schemas', version, '%s.json' % name, package=package) return json.loads(schema_string.decode('utf-8')) def get_item_properties(item, fields, mixed_case_fields=[], formatters={}): """Return a tuple containing the item properties. :param item: a single item resource (e.g. Server, Tenant, etc) :param fields: tuple of strings with the desired field names :param mixed_case_fields: tuple of field names to preserve case :param formatters: dictionary mapping field names to callables to format the values """ row = [] for field in fields: if field in formatters: row.append(formatters[field](item)) else: if field in mixed_case_fields: field_name = field.replace(' ', '_') else: field_name = field.lower().replace(' ', '_') if not hasattr(item, field_name) and \ (isinstance(item, dict) and field_name in item): data = item[field_name] else: data = getattr(item, field_name, '') if data is None: data = '' row.append(data) return tuple(row) def get_columns(data): """ Some row's might have variable count of columns, ensure that we have the same. :param data: Results in [{}, {]}] """ columns = set() def _seen(col): columns.add(str(col)) six.moves.map(lambda item: six.moves.map(_seen, list(six.iterkeys(item))), data) return list(columns) @removals.removed_kwarg('all_tenants', removal_version='1.3.0') @removals.removed_kwarg('edit_managed', removal_version='1.3.0') def get_session(auth_url, endpoint, domain_id, domain_name, project_id, project_name, project_domain_name, project_domain_id, username, user_id, password, user_domain_id, user_domain_name, token, insecure, cacert, all_tenants=False, edit_managed=False): # NOTE: all_tenants and edit_managed are here for backwards compat # reasons, do not add additional modifiers here. session = ks_session.Session() # Build + Attach Authentication Plugin auth_args = { 'auth_url': auth_url, 'domain_id': domain_id, 'domain_name': domain_name, 'project_id': project_id, 'project_name': project_name, 'project_domain_name': project_domain_name, 'project_domain_id': project_domain_id, } if token and endpoint: session.auth = token_endpoint.Token(endpoint, token) elif token: auth_args.update({ 'token': token }) session.auth = generic.Token(**auth_args) else: auth_args.update({ 'username': username, 'user_id': user_id, 'password': password, 'user_domain_id': user_domain_id, 'user_domain_name': user_domain_name, }) session.auth = generic.Password(**auth_args) # SSL/TLS Server Cert Verification if insecure is True: session.verify = False else: session.verify = cacert # NOTE: all_tenants and edit_managed are here for backwards compat # reasons, do not add additional modifiers here. session.all_tenants = all_tenants session.edit_managed = edit_managed return session def find_resourceid_by_name_or_id(resource_client, name_or_id): """Find resource id from its id or name.""" try: # Try to return an uuid return str(uuid.UUID(name_or_id)) except ValueError: # Not an uuid => assume it is resource name pass resources = resource_client.list() candidate_ids = [r['id'] for r in resources if r.get('name') == name_or_id] if not candidate_ids: raise exceptions.ResourceNotFound( 'Could not find resource with name "%s"' % name_or_id) elif len(candidate_ids) > 1: str_ids = ','.join(candidate_ids) raise exceptions.NoUniqueMatch( 'Multiple resources with name "%s": %s' % (name_or_id, str_ids)) return candidate_ids[0] class AdapterWithTimeout(adapter.Adapter): """adapter.Adapter wraps around a Session. The user can pass a timeout keyword that will apply only to the Designate Client, in order: - timeout keyword passed to ``request()`` - timeout keyword passed to ``AdapterWithTimeout()`` - timeout attribute on keystone session """ def __init__(self, *args, **kw): self.timeout = kw.pop('timeout', None) super(self.__class__, self).__init__(*args, **kw) def request(self, *args, **kwargs): if self.timeout is not None: kwargs.setdefault('timeout', self.timeout) return super(AdapterWithTimeout, self).request(*args, **kwargs) python-designateclient-2.11.0/designateclient/client.py0000666000175000017500000000732513366577761023326 0ustar zuulzuul00000000000000# Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import abc import json import six from six.moves.urllib import parse from stevedore import extension from designateclient import exceptions @six.add_metaclass(abc.ABCMeta) class Controller(object): def __init__(self, client): self.client = client def build_url(self, url, criterion=None, marker=None, limit=None): params = criterion or {} if marker is not None: params['marker'] = marker if limit is not None: params['limit'] = limit q = parse.urlencode(params) if params else '' return '%(url)s%(params)s' % { 'url': url, 'params': '?%s' % q } def _serialize(self, kwargs): headers = kwargs.get('headers') content_type = headers.get('Content-Type') if headers else None if 'data' in kwargs and content_type in {None, 'application/json'}: kwargs['data'] = json.dumps(kwargs['data']) def _post(self, url, response_key=None, **kwargs): self._serialize(kwargs) resp, body = self.client.session.post(url, **kwargs) if response_key is not None: return body[response_key] return body def _get(self, url, response_key=None): resp, body = self.client.session.get(url) if response_key is not None: return body[response_key] return body def _patch(self, url, response_key=None, **kwargs): self._serialize(kwargs) resp, body = self.client.session.patch(url, **kwargs) if response_key is not None: return body[response_key] return body def _put(self, url, response_key=None, **kwargs): self._serialize(kwargs) resp, body = self.client.session.put(url, **kwargs) if response_key is not None: return body[response_key] return body def _delete(self, url, response_key=None, **kwargs): resp, body = self.client.session.delete(url, **kwargs) if response_key is not None: return body[response_key] return body @six.add_metaclass(abc.ABCMeta) class CrudController(Controller): @abc.abstractmethod def list(self, *args, **kw): """ List a resource """ @abc.abstractmethod def get(self, *args, **kw): """ Get a resource """ @abc.abstractmethod def create(self, *args, **kw): """ Create a resource """ @abc.abstractmethod def update(self, *args, **kw): """ Update a resource """ @abc.abstractmethod def delete(self, *args, **kw): """ Delete a resource """ def get_versions(): mgr = extension.ExtensionManager('designateclient.versions') return dict([(ep.name, ep.plugin) for ep in mgr.extensions]) def Client(version, *args, **kwargs): # noqa versions = get_versions() if version not in versions: msg = 'Version %s is not supported, use one of (%s)' % ( version, list(six.iterkeys(versions))) raise exceptions.UnsupportedVersion(msg) return versions[version](*args, **kwargs) python-designateclient-2.11.0/designateclient/v2/0000775000175000017500000000000013366600247021776 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/v2/pools.py0000666000175000017500000000144413366577761023527 0ustar zuulzuul00000000000000# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. from designateclient.v2.base import V2Controller class PoolController(V2Controller): def list(self): url = '/pools' return self._get(url, response_key='pools') python-designateclient-2.11.0/designateclient/v2/service_statuses.py0000666000175000017500000000207113366577761025763 0ustar zuulzuul00000000000000# Copyright 2016 Hewlett Packard Enterprise Development Company LP # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.v2 import base class ServiceStatusesController(base.V2Controller): def list(self, criterion=None, marker=None, limit=None): url = self.build_url('/service_statuses', criterion, marker, limit) return self._get(url, response_key="service_statuses") def get(self, service_status_id): url = '/service_statuses/%s' % service_status_id return self._get(url) python-designateclient-2.11.0/designateclient/v2/__init__.py0000666000175000017500000000000013366577761024115 0ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/v2/zones.py0000666000175000017500000001217113366577761023530 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.v2.base import V2Controller from designateclient.v2 import utils as v2_utils class ZoneController(V2Controller): def create(self, name, type_=None, email=None, description=None, ttl=None, masters=None, attributes=None): type_ = type_ or "PRIMARY" data = { "name": name, "type": type_ } if type_ == "PRIMARY": if email: data["email"] = email if ttl is not None: data["ttl"] = ttl elif type_ == "SECONDARY" and masters: data["masters"] = masters if description is not None: data["description"] = description if attributes is not None: data["attributes"] = attributes return self._post('/zones', data=data) def list(self, criterion=None, marker=None, limit=None): url = self.build_url('/zones', criterion, marker, limit) return self._get(url, response_key="zones") def get(self, zone): zone = v2_utils.resolve_by_name(self.list, zone) return self._get('/zones/%s' % zone) def update(self, zone, values): zone = v2_utils.resolve_by_name(self.list, zone) url = self.build_url('/zones/%s' % zone) return self._patch(url, data=values) def delete(self, zone): zone = v2_utils.resolve_by_name(self.list, zone) url = self.build_url('/zones/%s' % zone) return self._delete(url) def abandon(self, zone): zone = v2_utils.resolve_by_name(self.list, zone) url = '/zones/%s/tasks/abandon' % zone self.client.session.post(url) def axfr(self, zone): zone = v2_utils.resolve_by_name(self.list, zone) url = '/zones/%s/tasks/xfr' % zone self.client.session.post(url) class ZoneTransfersController(V2Controller): def create_request(self, zone, target_project_id, description=None): zone = v2_utils.resolve_by_name(self.client.zones.list, zone) data = { "target_project_id": target_project_id } if description is not None: data["description"] = description url = '/zones/%s/tasks/transfer_requests' % zone return self._post(url, data=data) def get_request(self, transfer_id): url = '/zones/tasks/transfer_requests/%s' % transfer_id return self._get(url) def list_requests(self): url = '/zones/tasks/transfer_requests' return self._get(url, response_key="transfer_requests") def update_request(self, transfer_id, values): url = '/zones/tasks/transfer_requests/%s' % transfer_id return self._patch(url, data=values) def delete_request(self, transfer_id): url = '/zones/tasks/transfer_requests/%s' % transfer_id self._delete(url) def accept_request(self, transfer_id, key): url = '/zones/tasks/transfer_accepts' data = { "key": key, "zone_transfer_request_id": transfer_id } return self._post(url, data=data) def get_accept(self, accept_id): url = '/zones/tasks/transfer_accepts/%s' % accept_id return self._get(url) def list_accepts(self): url = '/zones/tasks/transfer_accepts' return self._get(url, response_key="transfer_accepts") class ZoneExportsController(V2Controller): def create(self, zone): zone_id = v2_utils.resolve_by_name(self.client.zones.list, zone) return self._post('/zones/%s/tasks/export' % zone_id) def get_export_record(self, zone_export_id): return self._get('/zones/tasks/exports/%s' % zone_export_id) def list(self): return self._get('/zones/tasks/exports') def delete(self, zone_export_id): return self._delete('/zones/tasks/exports/%s' % zone_export_id) def get_export(self, zone_export_id): return self._get('/zones/tasks/exports/%s/export' % zone_export_id, headers={'Accept': 'text/dns'}) class ZoneImportsController(V2Controller): def create(self, zone_file_contents): return self._post('/zones/tasks/imports', data=zone_file_contents, headers={'Content-Type': 'text/dns'}) def get_import_record(self, zone_import_id): return self._get('/zones/tasks/imports/%s' % zone_import_id) def list(self): return self._get('/zones/tasks/imports') def delete(self, zone_import_id): return self._delete('/zones/tasks/imports/%s' % zone_import_id) python-designateclient-2.11.0/designateclient/v2/cli/0000775000175000017500000000000013366600247022545 5ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/v2/cli/service_statuses.py0000666000175000017500000000570213366577761026536 0ustar zuulzuul00000000000000# Copyright 2016 Hewlett Packard Enterprise Development Company LP # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from osc_lib.command import command import six from designateclient import utils from designateclient.v2.cli import common from designateclient.v2 import utils as v2_utils LOG = logging.getLogger(__name__) def _format_status(status): status.pop("links", None) # Remove unneeded fields for display output formatting for k in ("capabilities", "stats"): status[k] = "\n".join(status[k]) if status[k] else "-" return status class ListServiceStatusesCommand(command.Lister): """List service statuses""" columns = ['id', 'hostname', 'service_name', 'status', 'stats', 'capabilities'] def get_parser(self, prog_name): parser = super(ListServiceStatusesCommand, self).get_parser(prog_name) parser.add_argument("--hostname", help="Hostname", required=False) parser.add_argument("--service_name", help="Service Name", required=False) parser.add_argument("--status", help="Status", required=False) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) cols = self.columns criterion = {} for i in ["hostname", "service_name", "status"]: v = getattr(parsed_args, i) if v is not None: criterion[i] = v data = v2_utils.get_all(client.service_statuses.list, criterion=criterion) for i, s in enumerate(data): data[i] = _format_status(s) return cols, (utils.get_item_properties(s, cols) for s in data) class ShowServiceStatusCommand(command.ShowOne): """Show service status details""" def get_parser(self, prog_name): parser = super(ShowServiceStatusCommand, self).get_parser(prog_name) parser.add_argument('id', help="Service Status ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.service_statuses.get(parsed_args.id) _format_status(data) return six.moves.zip(*sorted(six.iteritems(data))) python-designateclient-2.11.0/designateclient/v2/cli/__init__.py0000666000175000017500000000000013366577761024664 0ustar zuulzuul00000000000000python-designateclient-2.11.0/designateclient/v2/cli/zones.py0000666000175000017500000005235713366577761024311 0ustar zuulzuul00000000000000# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from osc_lib.command import command from osc_lib import exceptions as osc_exc import six from designateclient import utils from designateclient.v2.cli import common from designateclient.v2.utils import get_all LOG = logging.getLogger(__name__) def _format_zone(zone): zone.pop('links', None) zone['masters'] = ", ".join(zone['masters']) attrib = '' for attr in zone['attributes']: attrib += "%s:%s\n" % (attr, zone['attributes'][attr]) zone['attributes'] = attrib def _format_zone_export_record(zone_export_record): zone_export_record.pop('links', None) def _format_zone_import_record(zone_import_record): zone_import_record.pop('links', None) class ListZonesCommand(command.Lister): """List zones""" columns = ['id', 'name', 'type', 'serial', 'status', 'action'] def get_parser(self, prog_name): parser = super(ListZonesCommand, self).get_parser(prog_name) parser.add_argument('--name', help="Zone Name", required=False) parser.add_argument('--email', help="Zone Email", required=False) parser.add_argument('--type', help="Zone Type", required=False) parser.add_argument('--ttl', help="Time To Live (Seconds)", required=False) parser.add_argument('--description', help="Description", required=False) parser.add_argument('--status', help="Zone Status", required=False) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) criterion = {} if parsed_args.type is not None: criterion["type"] = parsed_args.type if parsed_args.name is not None: criterion["name"] = parsed_args.name if parsed_args.ttl is not None: criterion["ttl"] = parsed_args.ttl if parsed_args.description is not None: criterion["description"] = parsed_args.description if parsed_args.email is not None: criterion["email"] = parsed_args.email if parsed_args.status is not None: criterion["status"] = parsed_args.status data = get_all(client.zones.list, criterion) cols = self.columns if client.session.all_projects: cols.insert(1, 'project_id') return cols, (utils.get_item_properties(s, cols) for s in data) class ShowZoneCommand(command.ShowOne): """Show zone details""" def get_parser(self, prog_name): parser = super(ShowZoneCommand, self).get_parser(prog_name) parser.add_argument('id', help="Zone ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zones.get(parsed_args.id) _format_zone(data) return six.moves.zip(*sorted(six.iteritems(data))) class CreateZoneCommand(command.ShowOne): """Create new zone""" def get_parser(self, prog_name): parser = super(CreateZoneCommand, self).get_parser(prog_name) parser.add_argument('name', help="Zone Name") parser.add_argument('--email', help="Zone Email") parser.add_argument('--type', help="Zone Type", default='PRIMARY') parser.add_argument('--ttl', type=int, help="Time To Live (Seconds)") parser.add_argument('--description', help="Description") parser.add_argument('--masters', help="Zone Masters", nargs='+') parser.add_argument('--attributes', help="Zone Attributes", nargs='+') common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) payload = {} if parsed_args.description: payload["description"] = parsed_args.description if parsed_args.attributes: payload["attributes"] = {} for attr in parsed_args.attributes: try: k, v = attr.split(':') payload["attributes"][k] = v except ValueError: msg = "Attribute '%s' is in an incorrect format. "\ "Attributes are : formated" raise osc_exc.CommandError(msg % attr) if parsed_args.type == 'PRIMARY': # email is just for PRIMARY. if not parsed_args.email: msg = "Zone type PRIMARY requires --email." raise osc_exc.CommandError(msg) payload["email"] = parsed_args.email # TTL is just valid for PRIMARY if parsed_args.ttl is not None: payload["ttl"] = parsed_args.ttl elif parsed_args.type == 'SECONDARY': payload["masters"] = parsed_args.masters else: msg = "Type %s is not supported. Please choose between " \ "PRIMARY or SECONDARY" raise osc_exc.CommandError(msg % parsed_args.type) data = client.zones.create( parsed_args.name, parsed_args.type, **payload) _format_zone(data) return six.moves.zip(*sorted(six.iteritems(data))) class SetZoneCommand(command.ShowOne): """Set zone properties""" def get_parser(self, prog_name): parser = super(SetZoneCommand, self).get_parser(prog_name) parser.add_argument('id', help="Zone ID") parser.add_argument('--email', help="Zone Email") parser.add_argument('--ttl', type=int, help="Time To Live (Seconds)") description_group = parser.add_mutually_exclusive_group() description_group.add_argument('--description', help="Description") description_group.add_argument('--no-description', action='store_true') parser.add_argument('--masters', help="Zone Masters", nargs='+') common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = {} # TODO(kiall): API needs updating.. this get is silly if parsed_args.email: data['email'] = parsed_args.email if parsed_args.ttl: data['ttl'] = parsed_args.ttl if parsed_args.no_description: data['description'] = None elif parsed_args.description: data['description'] = parsed_args.description if parsed_args.masters: data['masters'] = parsed_args.masters updated = client.zones.update(parsed_args.id, data) _format_zone(updated) return six.moves.zip(*sorted(six.iteritems(updated))) class DeleteZoneCommand(command.ShowOne): """Delete zone""" def get_parser(self, prog_name): parser = super(DeleteZoneCommand, self).get_parser(prog_name) parser.add_argument('id', help="Zone ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zones.delete(parsed_args.id) LOG.info('Zone %s was deleted', parsed_args.id) _format_zone(data) return six.moves.zip(*sorted(six.iteritems(data))) class AbandonZoneCommand(command.Command): """Abandon a zone""" def get_parser(self, prog_name): parser = super(AbandonZoneCommand, self).get_parser(prog_name) parser.add_argument('id', help="Zone ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) client.zones.abandon(parsed_args.id) LOG.info("Z %(zone_id)s abandoned", {"zone_id": parsed_args.id}) class AXFRZoneCommand(command.Command): """AXFR a zone""" def get_parser(self, prog_name): parser = super(AXFRZoneCommand, self).get_parser(prog_name) parser.add_argument('id', help="Zone ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) client.zones.axfr(parsed_args.id) LOG.info("Scheduled AXFR for zone %(zone_id)s", {"zone_id": parsed_args.id}) class CreateTransferRequestCommand(command.ShowOne): """Create new zone transfer request""" def get_parser(self, prog_name): parser = super(CreateTransferRequestCommand, self).get_parser( prog_name) parser.add_argument('zone_id', help="Zone ID to transfer.",) parser.add_argument( '--target-project-id', help="Target Project ID to transfer to.") parser.add_argument('--description', help="Description") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_transfers.create_request( parsed_args.zone_id, parsed_args.target_project_id, parsed_args.description) return six.moves.zip(*sorted(six.iteritems(data))) class ListTransferRequestsCommand(command.Lister): """List Zone Transfer Requests""" columns = ['id', 'zone_id', 'zone_name', 'project_id', 'target_project_id', 'status', 'key'] def get_parser(self, prog_name): parser = super(ListTransferRequestsCommand, self).get_parser( prog_name) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_transfers.list_requests() cols = self.columns return cols, (utils.get_item_properties(s, cols) for s in data) class ShowTransferRequestCommand(command.ShowOne): """Show Zone Transfer Request Details""" def get_parser(self, prog_name): parser = super(ShowTransferRequestCommand, self).get_parser(prog_name) parser.add_argument('id', help="Zone Tranfer Request ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_transfers.get_request(parsed_args.id) return six.moves.zip(*sorted(six.iteritems(data))) class SetTransferRequestCommand(command.ShowOne): """Set a Zone Transfer Request""" def get_parser(self, prog_name): parser = super(SetTransferRequestCommand, self).get_parser(prog_name) parser.add_argument('id', help="Zone Transfer Request ID") description_group = parser.add_mutually_exclusive_group() description_group.add_argument('--description', help="Description") description_group.add_argument('--no-description', action='store_true') common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = {} if parsed_args.no_description: data['description'] = None elif parsed_args.description: data['description'] = parsed_args.description updated = client.zone_transfers.update_request(parsed_args.id, data) return six.moves.zip(*sorted(six.iteritems(updated))) class DeleteTransferRequestCommand(command.Command): """Delete a Zone Transfer Request""" def get_parser(self, prog_name): parser = super(DeleteTransferRequestCommand, self).get_parser( prog_name) parser.add_argument('id', help="Zone Transfer Request ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) client.zone_transfers.delete_request(parsed_args.id) LOG.info('Zone Transfer %s was deleted', parsed_args.id) class AcceptTransferRequestCommand(command.ShowOne): """Accept a Zone Transfer Request""" def get_parser(self, prog_name): parser = super(AcceptTransferRequestCommand, self).get_parser( prog_name) parser.add_argument('--transfer-id', help="Transfer ID", type=str, required=True) parser.add_argument('--key', help="Transfer Key", type=str, required=True) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_transfers.accept_request( parsed_args.transfer_id, parsed_args.key) return six.moves.zip(*sorted(six.iteritems(data))) class ListTransferAcceptsCommand(command.Lister): """List Zone Transfer Accepts""" columns = ['id', 'zone_id', 'project_id', 'zone_transfer_request_id', 'status', 'key'] def get_parser(self, prog_name): parser = super(ListTransferAcceptsCommand, self).get_parser( prog_name) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_transfers.list_requests() cols = self.columns return cols, (utils.get_item_properties(s, cols) for s in data) class ShowTransferAcceptCommand(command.ShowOne): """Show Zone Transfer Accept""" def get_parser(self, prog_name): parser = super(ShowTransferAcceptCommand, self).get_parser(prog_name) parser.add_argument('id', help="Zone Tranfer Accept ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_transfers.get_accept(parsed_args.id) return six.moves.zip(*sorted(six.iteritems(data))) class ExportZoneCommand(command.ShowOne): """Export a Zone""" def get_parser(self, prog_name): parser = super(ExportZoneCommand, self).get_parser( prog_name) common.add_all_common_options(parser) parser.add_argument('zone_id', help="Zone ID", type=str) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_exports.create(parsed_args.zone_id) _format_zone_export_record(data) LOG.info('Zone Export %s was created', data['id']) return six.moves.zip(*sorted(six.iteritems(data))) class ListZoneExportsCommand(command.Lister): """List Zone Exports""" columns = [ 'id', 'zone_id', 'created_at', 'status', ] def get_parser(self, prog_name): parser = super(ListZoneExportsCommand, self).get_parser( prog_name) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_exports.list() cols = self.columns return cols, (utils.get_item_properties(s, cols) for s in data['exports']) class ShowZoneExportCommand(command.ShowOne): """Show a Zone Export""" def get_parser(self, prog_name): parser = super(ShowZoneExportCommand, self).get_parser( prog_name) parser.add_argument('zone_export_id', help="Zone Export ID", type=str) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_exports.get_export_record( parsed_args.zone_export_id) _format_zone_export_record(data) return six.moves.zip(*sorted(six.iteritems(data))) class DeleteZoneExportCommand(command.Command): """Delete a Zone Export""" def get_parser(self, prog_name): parser = super(DeleteZoneExportCommand, self).get_parser( prog_name) parser.add_argument('zone_export_id', help="Zone Export ID", type=str) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) client.zone_exports.delete(parsed_args.zone_export_id) LOG.info('Zone Export %s was deleted', parsed_args.zone_export_id) class ShowZoneExportFileCommand(command.ShowOne): """Show the zone file for the Zone Export""" def get_parser(self, prog_name): parser = super(ShowZoneExportFileCommand, self).get_parser( prog_name) parser.add_argument('zone_export_id', help="Zone Export ID", type=str) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_exports.get_export(parsed_args.zone_export_id) return ['data'], [data] class ImportZoneCommand(command.ShowOne): """Import a Zone from a file on the filesystem""" def get_parser(self, prog_name): parser = super(ImportZoneCommand, self).get_parser( prog_name) parser.add_argument('zone_file_path', help="Path to a zone file", type=str) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) with open(parsed_args.zone_file_path, 'r') as f: zone_file_contents = f.read() data = client.zone_imports.create(zone_file_contents) _format_zone_import_record(data) LOG.info('Zone Import %s was created', data['id']) return six.moves.zip(*sorted(six.iteritems(data))) class ListZoneImportsCommand(command.Lister): """List Zone Imports""" columns = [ 'id', 'zone_id', 'created_at', 'status', 'message', ] def get_parser(self, prog_name): parser = super(ListZoneImportsCommand, self).get_parser( prog_name) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_imports.list() cols = self.columns return cols, (utils.get_item_properties(s, cols) for s in data['imports']) class ShowZoneImportCommand(command.ShowOne): """Show a Zone Import""" def get_parser(self, prog_name): parser = super(ShowZoneImportCommand, self).get_parser( prog_name) parser.add_argument('zone_import_id', help="Zone Import ID", type=str) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.zone_imports.get_import_record( parsed_args.zone_import_id) _format_zone_import_record(data) return six.moves.zip(*sorted(six.iteritems(data))) class DeleteZoneImportCommand(command.Command): """Delete a Zone Import""" def get_parser(self, prog_name): parser = super(DeleteZoneImportCommand, self).get_parser( prog_name) parser.add_argument('zone_import_id', help="Zone Import ID", type=str) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) client.zone_imports.delete(parsed_args.zone_import_id) LOG.info('Zone Import %s was deleted', parsed_args.zone_import_id) python-designateclient-2.11.0/designateclient/v2/cli/recordsets.py0000666000175000017500000002144313366577761025320 0ustar zuulzuul00000000000000# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import argparse import logging from osc_lib.command import command import six from designateclient import utils from designateclient.v2.cli import common from designateclient.v2.utils import get_all LOG = logging.getLogger(__name__) def _format_recordset(recordset): # Remove unneeded fields for display output formatting recordset['records'] = "\n".join(recordset['records']) recordset.pop('links', None) return recordset def _has_project_id(data): if len(data) < 1: return False if 'project_id' in data[0]: return True return False class ListRecordSetsCommand(command.Lister): """List recordsets""" columns = ['id', 'name', 'type', 'records', 'status', 'action'] def get_parser(self, prog_name): parser = super(ListRecordSetsCommand, self).get_parser(prog_name) parser.add_argument('--name', help="RecordSet Name", required=False) parser.add_argument('--type', help="RecordSet Type", required=False) parser.add_argument('--data', help="RecordSet Record Data", required=False) parser.add_argument('--ttl', help="Time To Live (Seconds)", required=False) parser.add_argument('--description', help="Description", required=False) parser.add_argument('--status', help="RecordSet Status", required=False) parser.add_argument('--action', help="RecordSet Action", required=False) parser.add_argument('zone_id', help="Zone ID. To list all" " recordsets specify 'all'") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) criterion = {} if parsed_args.type is not None: criterion["type"] = parsed_args.type if parsed_args.name is not None: criterion["name"] = parsed_args.name if parsed_args.data is not None: criterion["data"] = parsed_args.data if parsed_args.ttl is not None: criterion["ttl"] = parsed_args.ttl if parsed_args.description is not None: criterion["description"] = parsed_args.description if parsed_args.status is not None: criterion["status"] = parsed_args.status if parsed_args.action is not None: criterion["action"] = parsed_args.action cols = self.columns if parsed_args.zone_id == 'all': data = get_all(client.recordsets.list_all_zones, criterion=criterion) cols.insert(2, 'zone_name') else: data = get_all(client.recordsets.list, args=[parsed_args.zone_id], criterion=criterion) if client.session.all_projects and _has_project_id(data): cols.insert(1, 'project_id') for i, rs in enumerate(data): data[i] = _format_recordset(rs) return cols, (utils.get_item_properties(s, cols) for s in data) class ShowRecordSetCommand(command.ShowOne): """Show recordset details""" def get_parser(self, prog_name): parser = super(ShowRecordSetCommand, self).get_parser(prog_name) parser.add_argument('zone_id', help="Zone ID") parser.add_argument('id', help="RecordSet ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.recordsets.get(parsed_args.zone_id, parsed_args.id) _format_recordset(data) return six.moves.zip(*sorted(six.iteritems(data))) class CreateRecordSetCommand(command.ShowOne): """Create new recordset""" log = logging.getLogger('deprecated') def get_parser(self, prog_name): parser = super(CreateRecordSetCommand, self).get_parser(prog_name) parser.add_argument('zone_id', help="Zone ID") parser.add_argument('name', help="RecordSet Name") req_group = parser.add_mutually_exclusive_group(required=True) req_group.add_argument( '--records', help=argparse.SUPPRESS, nargs='+') req_group.add_argument( '--record', help="RecordSet Record, repeat if necessary", action='append') parser.add_argument('--type', help="RecordSet Type", required=True) parser.add_argument('--ttl', type=int, help="Time To Live (Seconds)") parser.add_argument('--description', help="Description") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) all_records = parsed_args.record or parsed_args.records if parsed_args.records: self.log.warning( "Option --records is deprecated, use --record instead.") data = client.recordsets.create( parsed_args.zone_id, parsed_args.name, parsed_args.type, all_records, description=parsed_args.description, ttl=parsed_args.ttl) _format_recordset(data) return six.moves.zip(*sorted(six.iteritems(data))) class SetRecordSetCommand(command.ShowOne): """Set recordset properties""" def get_parser(self, prog_name): parser = super(SetRecordSetCommand, self).get_parser(prog_name) parser.add_argument('zone_id', help="Zone ID") parser.add_argument('id', help="RecordSet ID") req_group = parser.add_mutually_exclusive_group() req_group.add_argument( '--records', help=argparse.SUPPRESS, nargs='+') req_group.add_argument( '--record', help="RecordSet Record, repeat if necessary", action='append') description_group = parser.add_mutually_exclusive_group() description_group.add_argument('--description', help="Description") description_group.add_argument('--no-description', action='store_true') ttl_group = parser.add_mutually_exclusive_group() ttl_group.add_argument('--ttl', type=int, help="TTL") ttl_group.add_argument('--no-ttl', action='store_true') common.add_all_common_options(parser) return parser def take_action(self, parsed_args): data = {} if parsed_args.no_description: data['description'] = None elif parsed_args.description: data['description'] = parsed_args.description if parsed_args.no_ttl: data['ttl'] = None elif parsed_args.ttl: data['ttl'] = parsed_args.ttl all_records = parsed_args.record or parsed_args.records if parsed_args.records: self.log.warning( "Option --records is deprecated, use --record instead.") if all_records: data['records'] = all_records client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) updated = client.recordsets.update( parsed_args.zone_id, parsed_args.id, data) _format_recordset(updated) return six.moves.zip(*sorted(six.iteritems(updated))) class DeleteRecordSetCommand(command.ShowOne): """Delete recordset""" def get_parser(self, prog_name): parser = super(DeleteRecordSetCommand, self).get_parser(prog_name) parser.add_argument('zone_id', help="Zone ID") parser.add_argument('id', help="RecordSet ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.recordsets.delete(parsed_args.zone_id, parsed_args.id) LOG.info('RecordSet %s was deleted', parsed_args.id) _format_recordset(data) return six.moves.zip(*sorted(six.iteritems(data))) python-designateclient-2.11.0/designateclient/v2/cli/common.py0000666000175000017500000000432113366577761024427 0ustar zuulzuul00000000000000# Copyright 2016 Hewlett Packard Enterprise Development Company LP # # Author: Graham Hayes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import six def add_all_projects_option(parser): parser.add_argument( '--all-projects', default=False, action='store_true', help='Show results from all projects. Default: False' ) def add_edit_managed_option(parser): parser.add_argument( '--edit-managed', default=False, action='store_true', help='Edit resources marked as managed. Default: False' ) def add_sudo_project_id_option(parser): parser.add_argument( '--sudo-project-id', default=None, help='Project ID to impersonate for this command. Default: None' ) def add_all_common_options(parser): add_all_projects_option(parser) add_edit_managed_option(parser) add_sudo_project_id_option(parser) def set_all_projects(client, value): client.session.all_projects = value def set_sudo_project_id(client, value): client.session.sudo_project_id = value def set_edit_managed(client, value): client.session.edit_managed = value def set_all_common_headers(client, parsed_args): if parsed_args.all_projects is not None and \ isinstance(parsed_args.all_projects, bool): set_all_projects(client, parsed_args.all_projects) if parsed_args.edit_managed is not None and \ isinstance(parsed_args.edit_managed, bool): set_edit_managed(client, parsed_args.edit_managed) if parsed_args.sudo_project_id is not None and \ isinstance(parsed_args.sudo_project_id, six.string_types): set_sudo_project_id(client, parsed_args.sudo_project_id) python-designateclient-2.11.0/designateclient/v2/cli/tsigkeys.py0000666000175000017500000001306313366577761025004 0ustar zuulzuul00000000000000# Copyright 2017 SAP SE # # Author: Rudolf Vriend # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from osc_lib.command import command import six from designateclient import utils from designateclient.v2.cli import common from designateclient.v2.utils import get_all LOG = logging.getLogger(__name__) def _format_tsigkey(tsigkey): # Remove unneeded fields for display output formatting tsigkey.pop('links', None) class ListTSIGKeysCommand(command.Lister): """List tsigkeys""" columns = ['id', 'name', 'algorithm', 'secret', 'scope', 'resource_id'] def get_parser(self, prog_name): parser = super(ListTSIGKeysCommand, self).get_parser(prog_name) parser.add_argument('--name', help="TSIGKey NAME", required=False) parser.add_argument('--algorithm', help="TSIGKey algorithm", required=False) parser.add_argument('--scope', help="TSIGKey scope", required=False) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) criterion = {} if parsed_args.name is not None: criterion["name"] = parsed_args.name if parsed_args.algorithm is not None: criterion["algorithm"] = parsed_args.algorithm if parsed_args.scope is not None: criterion["scope"] = parsed_args.scope data = get_all(client.tsigkeys.list, criterion) cols = self.columns return cols, (utils.get_item_properties(s, cols) for s in data) class ShowTSIGKeyCommand(command.ShowOne): """Show tsigkey details""" def get_parser(self, prog_name): parser = super(ShowTSIGKeyCommand, self).get_parser(prog_name) parser.add_argument('id', help="TSIGKey ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.tsigkeys.get(parsed_args.id) _format_tsigkey(data) return six.moves.zip(*sorted(six.iteritems(data))) class CreateTSIGKeyCommand(command.ShowOne): """Create new tsigkey""" def get_parser(self, prog_name): parser = super(CreateTSIGKeyCommand, self).get_parser(prog_name) parser.add_argument('--name', help="TSIGKey Name", required=True) parser.add_argument('--algorithm', help="TSIGKey algorithm", required=True) parser.add_argument('--secret', help="TSIGKey secret", required=True) parser.add_argument('--scope', help="TSIGKey scope", required=True) parser.add_argument('--resource-id', help="TSIGKey resource_id", required=True) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.tsigkeys.create(parsed_args.name, parsed_args.algorithm, parsed_args.secret, parsed_args.scope, parsed_args.resource_id) _format_tsigkey(data) return six.moves.zip(*sorted(six.iteritems(data))) class SetTSIGKeyCommand(command.ShowOne): """Set tsigkey properties""" def get_parser(self, prog_name): parser = super(SetTSIGKeyCommand, self).get_parser(prog_name) parser.add_argument('id', help="TSIGKey ID") parser.add_argument('--name', help="TSIGKey Name") parser.add_argument('--algorithm', help="TSIGKey algorithm") parser.add_argument('--secret', help="TSIGKey secret") parser.add_argument('--scope', help="TSIGKey scope") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): data = {} if parsed_args.name: data['name'] = parsed_args.name if parsed_args.algorithm: data['algorithm'] = parsed_args.algorithm if parsed_args.secret: data['secret'] = parsed_args.secret if parsed_args.scope: data['scope'] = parsed_args.scope client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.tsigkeys.update(parsed_args.id, data) _format_tsigkey(data) return six.moves.zip(*sorted(six.iteritems(data))) class DeleteTSIGKeyCommand(command.Command): """Delete tsigkey""" def get_parser(self, prog_name): parser = super(DeleteTSIGKeyCommand, self).get_parser(prog_name) parser.add_argument('id', help="TSIGKey ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) client.tsigkeys.delete(parsed_args.id) LOG.info('TSIGKey %s was deleted', parsed_args.id) python-designateclient-2.11.0/designateclient/v2/cli/reverse.py0000666000175000017500000001077413366577761024623 0ustar zuulzuul00000000000000# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from osc_lib.command import command import six from designateclient import utils from designateclient.v2.cli import common from designateclient.v2.utils import get_all LOG = logging.getLogger(__name__) def _format_floatingip(fip): # Remove unneeded fields for display output formatting fip.pop('links', None) class ListFloatingIPCommand(command.Lister): """List floatingip ptr records""" columns = ['id', 'ptrdname', 'description', 'ttl'] def get_parser(self, prog_name): parser = super(ListFloatingIPCommand, self).get_parser(prog_name) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) cols = self.columns data = get_all(client.floatingips.list) return cols, (utils.get_item_properties(s, cols) for s in data) class ShowFloatingIPCommand(command.ShowOne): """Show floatingip ptr record details""" def get_parser(self, prog_name): parser = super(ShowFloatingIPCommand, self).get_parser(prog_name) parser.add_argument('floatingip_id', help="Floating IP ID in format " "region:floatingip_id") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.floatingips.get(parsed_args.floatingip_id) _format_floatingip(data) return six.moves.zip(*sorted(six.iteritems(data))) class SetFloatingIPCommand(command.ShowOne): """Set floatingip ptr record""" def get_parser(self, prog_name): parser = super(SetFloatingIPCommand, self).get_parser(prog_name) parser.add_argument('floatingip_id', help="Floating IP ID in format " "region:floatingip_id") parser.add_argument('ptrdname', help="PTRD Name") description_group = parser.add_mutually_exclusive_group() description_group.add_argument('--description', help="Description") description_group.add_argument('--no-description', action='store_true') ttl_group = parser.add_mutually_exclusive_group() ttl_group.add_argument('--ttl', type=int, help="TTL") ttl_group.add_argument('--no-ttl', action='store_true') common.add_all_common_options(parser) return parser def take_action(self, parsed_args): data = {} if parsed_args.no_description: data['description'] = None elif parsed_args.description: data['description'] = parsed_args.description if parsed_args.no_ttl: data['ttl'] = None elif parsed_args.ttl: data['ttl'] = parsed_args.ttl client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) fip = client.floatingips.set( parsed_args.floatingip_id, parsed_args.ptrdname, parsed_args.description, parsed_args.ttl) _format_floatingip(fip) return six.moves.zip(*sorted(six.iteritems(fip))) class UnsetFloatingIPCommand(command.Command): """Unset floatingip ptr record""" def get_parser(self, prog_name): parser = super(UnsetFloatingIPCommand, self).get_parser(prog_name) parser.add_argument('floatingip_id', help="Floating IP ID in format " "region:floatingip_id") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) client.floatingips.unset(parsed_args.floatingip_id) LOG.info('FloatingIP PTR %s was unset', parsed_args.floatingip_id) python-designateclient-2.11.0/designateclient/v2/cli/blacklists.py0000666000175000017500000001121313366577761025270 0ustar zuulzuul00000000000000# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from osc_lib.command import command import six from designateclient import utils from designateclient.v2.cli import common from designateclient.v2.utils import get_all LOG = logging.getLogger(__name__) def _format_blacklist(blacklist): # Remove unneeded fields for display output formatting blacklist.pop('links', None) class ListBlacklistsCommand(command.Lister): """List blacklists""" columns = ['id', 'pattern', 'description'] def get_parser(self, prog_name): parser = super(ListBlacklistsCommand, self).get_parser(prog_name) common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) cols = self.columns data = get_all(client.blacklists.list) return cols, (utils.get_item_properties(s, cols) for s in data) class ShowBlacklistCommand(command.ShowOne): """Show blacklist details""" def get_parser(self, prog_name): parser = super(ShowBlacklistCommand, self).get_parser(prog_name) parser.add_argument('id', help="Blacklist ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.blacklists.get(parsed_args.id) _format_blacklist(data) return six.moves.zip(*sorted(six.iteritems(data))) class CreateBlacklistCommand(command.ShowOne): """Create new blacklist""" def get_parser(self, prog_name): parser = super(CreateBlacklistCommand, self).get_parser(prog_name) parser.add_argument('--pattern', help="Blacklist pattern", required=True) parser.add_argument('--description', help="Description") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.blacklists.create( parsed_args.pattern, parsed_args.description) _format_blacklist(data) return six.moves.zip(*sorted(six.iteritems(data))) class SetBlacklistCommand(command.ShowOne): """Set blacklist properties""" def get_parser(self, prog_name): parser = super(SetBlacklistCommand, self).get_parser(prog_name) parser.add_argument('id', help="Blacklist ID") parser.add_argument('--pattern', help="Blacklist pattern") description_group = parser.add_mutually_exclusive_group() description_group.add_argument('--description', help="Description") description_group.add_argument('--no-description', action='store_true') common.add_all_common_options(parser) return parser def take_action(self, parsed_args): data = {} if parsed_args.pattern: data['pattern'] = parsed_args.pattern if parsed_args.no_description: data['description'] = None elif parsed_args.description: data['description'] = parsed_args.description client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) updated = client.blacklists.update(parsed_args.id, data) _format_blacklist(updated) return six.moves.zip(*sorted(six.iteritems(updated))) class DeleteBlacklistCommand(command.Command): """Delete blacklist""" def get_parser(self, prog_name): parser = super(DeleteBlacklistCommand, self).get_parser(prog_name) parser.add_argument('id', help="Blacklist ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) client.blacklists.delete(parsed_args.id) LOG.info('Blacklist %s was deleted', parsed_args.id) python-designateclient-2.11.0/designateclient/v2/cli/quotas.py0000666000175000017500000000755113366577761024463 0ustar zuulzuul00000000000000# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import itertools import logging from cliff import command from cliff import show import six from designateclient.v2.cli import common LOG = logging.getLogger(__name__) DNS_QUOTAS = { "api_export_size": "api-export-size", "recordset_records": "recordset-records", "zone_records": "zone-records", "zone_recordsets": "zone-recordsets", "zones": "zones" } class ListQuotasCommand(show.ShowOne): """List quotas""" # columns = ['resource', 'hard_limit'] def get_parser(self, prog_name): parser = super(ListQuotasCommand, self).get_parser(prog_name) common.add_all_common_options(parser) parser.add_argument( '--project-id', help="Project ID Default: current project") return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) proj_id = parsed_args.project_id or client.session.get_project_id() if parsed_args.project_id != client.session.get_project_id(): common.set_all_projects(client, True) data = client.quotas.list(proj_id) return six.moves.zip(*sorted(six.iteritems(data))) class SetQuotasCommand(show.ShowOne): """Set quotas""" def _build_options_list(self): return itertools.chain(DNS_QUOTAS.items()) def get_parser(self, prog_name): parser = super(SetQuotasCommand, self).get_parser(prog_name) common.add_all_common_options(parser) parser.add_argument('--project-id', help="Project ID") for k, v in self._build_options_list(): parser.add_argument( '--%s' % v, metavar='<%s>' % v, dest=k, type=int, help='New value for the %s quota' % v, ) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) quotas = {} for k, v in DNS_QUOTAS.items(): value = getattr(parsed_args, k, None) if value is not None: quotas[k] = value proj_id = parsed_args.project_id or client.session.get_project_id() if parsed_args.project_id != client.session.get_project_id(): common.set_all_projects(client, True) updated = client.quotas.update(proj_id, quotas) return six.moves.zip(*sorted(six.iteritems(updated))) class ResetQuotasCommand(command.Command): """Reset quotas""" def get_parser(self, prog_name): parser = super(ResetQuotasCommand, self).get_parser(prog_name) common.add_all_common_options(parser) parser.add_argument('--project-id', help="Project ID") return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) proj_id = parsed_args.project_id or client.session.get_project_id() if parsed_args.project_id != client.session.get_project_id(): common.set_all_projects(client, True) client.quotas.reset(proj_id) LOG.info('Quota for project %s was reset', parsed_args.project_id) python-designateclient-2.11.0/designateclient/v2/cli/tlds.py0000666000175000017500000001077113366577761024113 0ustar zuulzuul00000000000000# Copyright 2014 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging from osc_lib.command import command import six from designateclient import utils from designateclient.v2.cli import common from designateclient.v2.utils import get_all LOG = logging.getLogger(__name__) def _format_tld(tld): # Remove unneeded fields for display output formatting tld.pop('links', None) class ListTLDsCommand(command.Lister): """List tlds""" columns = ['id', 'name', 'description'] def get_parser(self, prog_name): parser = super(ListTLDsCommand, self).get_parser(prog_name) parser.add_argument('--name', help="TLD NAME") parser.add_argument('--description', help="TLD Description") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = get_all(client.tlds.list) cols = self.columns return cols, (utils.get_item_properties(s, cols) for s in data) class ShowTLDCommand(command.ShowOne): """Show tld details""" def get_parser(self, prog_name): parser = super(ShowTLDCommand, self).get_parser(prog_name) parser.add_argument('id', help="TLD ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.tlds.get(parsed_args.id) _format_tld(data) return six.moves.zip(*sorted(six.iteritems(data))) class CreateTLDCommand(command.ShowOne): """Create new tld""" def get_parser(self, prog_name): parser = super(CreateTLDCommand, self).get_parser(prog_name) parser.add_argument('--name', help="TLD Name", required=True) parser.add_argument('--description', help="Description") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.tlds.create(parsed_args.name, parsed_args.description) _format_tld(data) return six.moves.zip(*sorted(six.iteritems(data))) class SetTLDCommand(command.ShowOne): """Set tld properties""" def get_parser(self, prog_name): parser = super(SetTLDCommand, self).get_parser(prog_name) parser.add_argument('id', help="TLD ID") parser.add_argument('--name', help="TLD Name") description_group = parser.add_mutually_exclusive_group() description_group.add_argument('--description', help="Description") description_group.add_argument('--no-description', action='store_true') common.add_all_common_options(parser) return parser def take_action(self, parsed_args): data = {} if parsed_args.name: data['name'] = parsed_args.name if parsed_args.no_description: data['description'] = None elif parsed_args.description: data['description'] = parsed_args.description client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) data = client.tlds.update(parsed_args.id, data) _format_tld(data) return six.moves.zip(*sorted(six.iteritems(data))) class DeleteTLDCommand(command.Command): """Delete tld""" def get_parser(self, prog_name): parser = super(DeleteTLDCommand, self).get_parser(prog_name) parser.add_argument('id', help="TLD ID") common.add_all_common_options(parser) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns common.set_all_common_headers(client, parsed_args) client.tlds.delete(parsed_args.id) LOG.info('TLD %s was deleted', parsed_args.id) python-designateclient-2.11.0/designateclient/v2/recordsets.py0000666000175000017500000000677713366577761024566 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from oslo_utils import uuidutils import six from designateclient.v2.base import V2Controller from designateclient.v2 import utils as v2_utils class RecordSetController(V2Controller): def _canonicalize_record_name(self, zone, name): zone_info = None # If we get a zone name we'll need to get the ID of it before POST. if isinstance(zone, six.string_types) and not \ uuidutils.is_uuid_like(zone): zone_info = self.client.zones.get(zone) elif isinstance(zone, dict): zone_info = zone # We where given a name like "www" vs www.i.io., attempt to fix it on # the behalf of the actor. if not name.endswith("."): if not isinstance(zone_info, dict): zone_info = self.client.zones.get(zone) name = "%s.%s" % (name, zone_info["name"]) return name, zone_info def create(self, zone, name, type_, records, description=None, ttl=None): name, zone_info = self._canonicalize_record_name(zone, name) data = { 'name': name, 'type': type_, 'records': records } if ttl is not None: data['ttl'] = ttl if description is not None: data['description'] = description if zone_info is not None: zone_id = zone_info["id"] else: zone_id = zone url = '/zones/%s/recordsets' % zone_id return self._post(url, data=data) def list(self, zone, criterion=None, marker=None, limit=None): zone = v2_utils.resolve_by_name(self.client.zones.list, zone) url = self.build_url( '/zones/%s/recordsets' % zone, criterion, marker, limit) return self._get(url, response_key='recordsets') def list_all_zones(self, criterion=None, marker=None, limit=None): url = self.build_url('/recordsets', criterion, marker, limit) return self._get(url, response_key='recordsets') def get(self, zone, recordset): zone = v2_utils.resolve_by_name(self.client.zones.list, zone) recordset = v2_utils.resolve_by_name(self.list, recordset, zone) url = self.build_url('/zones/%s/recordsets/%s' % ( zone, recordset)) return self._get(url) def update(self, zone, recordset, values): zone = v2_utils.resolve_by_name(self.client.zones.list, zone) recordset = v2_utils.resolve_by_name(self.list, recordset, zone) url = '/zones/%s/recordsets/%s' % (zone, recordset) return self._put(url, data=values) def delete(self, zone, recordset): zone = v2_utils.resolve_by_name(self.client.zones.list, zone) recordset = v2_utils.resolve_by_name(self.list, recordset, zone) url = '/zones/%s/recordsets/%s' % (zone, recordset) return self._delete(url) python-designateclient-2.11.0/designateclient/v2/limits.py0000666000175000017500000000143613366577761023675 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.v2.base import V2Controller class LimitController(V2Controller): def get(self): return self._get('/limits') python-designateclient-2.11.0/designateclient/v2/tsigkeys.py0000666000175000017500000000326313366577761024236 0ustar zuulzuul00000000000000# Copyright 2017 SAP SE # # Author: Rudolf Vriend # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.v2.base import V2Controller from designateclient.v2 import utils as v2_utils class TSIGKeysController(V2Controller): def create(self, name, algorithm, secret, scope, resource_id): data = { 'name': name, 'algorithm': algorithm, 'secret': secret, 'scope': scope, 'resource_id': resource_id } return self._post('/tsigkeys', data=data) def list(self, criterion=None, marker=None, limit=None): url = self.build_url('/tsigkeys', criterion, marker, limit) return self._get(url, response_key='tsigkeys') def get(self, tsigkey): tsigkey = v2_utils.resolve_by_name(self.list, tsigkey) return self._get('/tsigkeys/%s' % tsigkey) def update(self, tsigkey, values): tsigkey = v2_utils.resolve_by_name(self.list, tsigkey) return self._patch('/tsigkeys/%s' % tsigkey, data=values) def delete(self, tsigkey): tsigkey = v2_utils.resolve_by_name(self.list, tsigkey) return self._delete('/tsigkeys/%s' % tsigkey) python-designateclient-2.11.0/designateclient/v2/base.py0000666000175000017500000000250713366577761023306 0ustar zuulzuul00000000000000# Copyright 2016 Hewlett Packard Enterprise Development Company LP # # Author: Graham Hayes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient import client from designateclient.v2.utils import parse_query_from_url class DesignateList(list): next_link_criterion = {} next_page = False class V2Controller(client.Controller): def _get(self, url, response_key=None, **kwargs): resp, body = self.client.session.get(url, **kwargs) if response_key is not None: data = DesignateList() data.extend(body[response_key]) if 'next' in body.get('links', {}): data.next_page = True data.next_link_criterion = parse_query_from_url( body['links']['next']) return data return body python-designateclient-2.11.0/designateclient/v2/reverse.py0000666000175000017500000000305013366577761024041 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.v2.base import V2Controller class FloatingIPController(V2Controller): def set(self, floatingip_id, ptrdname, description=None, ttl=None): data = { 'ptrdname': ptrdname } if description is not None: data["description"] = description if ttl is not None: data["ttl"] = ttl url = '/reverse/floatingips/%s' % floatingip_id return self._patch(url, data=data) def list(self, criterion=None): url = self.build_url('/reverse/floatingips', criterion) return self._get(url, response_key='floatingips') def get(self, floatingip_id): url = '/reverse/floatingips/%s' % floatingip_id return self._get(url) def unset(self, floatingip_id): data = {"ptrdname": None} url = '/reverse/floatingips/%s' % floatingip_id return self._patch(url, data=data) python-designateclient-2.11.0/designateclient/v2/nameservers.py0000666000175000017500000000174613366577761024732 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.v2.base import V2Controller from designateclient.v2 import utils as v2_utils class NameServerController(V2Controller): def list(self, zone): zone = v2_utils.resolve_by_name(self.client.zones.list, zone) url = '/zones/%s/nameservers' % zone return self._get(url, response_key='nameservers') python-designateclient-2.11.0/designateclient/v2/utils.py0000666000175000017500000000455313366577761023537 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from oslo_utils import uuidutils from six import iteritems from six import iterkeys from six.moves.urllib.parse import parse_qs from six.moves.urllib.parse import urlparse from designateclient import exceptions def resolve_by_name(func, name, *args): """ Helper to resolve a "name" a'la foo.com to it's ID by using REST api's query support and filtering on name. """ if uuidutils.is_uuid_like(name): return name results = func(criterion={"name": "%s" % name}, *args) length = len(results) if length == 1: return results[0]["id"] elif length == 0: raise exceptions.NotFound("Name %s didn't resolve" % name) else: msg = "Multiple matches found for %s, please use ID instead." % name raise exceptions.NoUniqueMatch(msg) def parse_query_from_url(url): """ Helper to get key bits of data from the "next" url returned from the API on collections :param url: :return: dict """ values = parse_qs(urlparse(url)[4]) return {k: values[k][0] for k in iterkeys(values)} def get_all(function, criterion=None, args=None): """ :param function: Function to be called to get data :param criterion: dict of filters to be applied :param args: arguments to be given to the function :return: DesignateList() """ criterion = criterion or {} args = args or [] data = function(*args, criterion=criterion) returned_data = data while True: if data.next_page: for k, v in iteritems(data.next_link_criterion): criterion[k] = v data = function(*args, criterion=criterion) returned_data.extend(data) else: break return returned_data python-designateclient-2.11.0/designateclient/v2/blacklists.py0000666000175000017500000000301213366577761024517 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.v2.base import V2Controller class BlacklistController(V2Controller): def create(self, pattern, description=None): data = { 'pattern': pattern, } if description is not None: data['description'] = description return self._post('/blacklists', data=data) def list(self, criterion=None, marker=None, limit=None): url = self.build_url('/blacklists', criterion, marker, limit) return self._get(url, response_key="blacklists") def get(self, blacklist_id): url = '/blacklists/%s' % blacklist_id return self._get(url) def update(self, blacklist_id, values): url = '/blacklists/%s' % blacklist_id return self._patch(url, data=values) def delete(self, blacklist_id): url = '/blacklists/%s' % blacklist_id return self._delete(url) python-designateclient-2.11.0/designateclient/v2/client.py0000666000175000017500000001304213366577761023646 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from keystoneauth1 import adapter from designateclient import exceptions from designateclient.v2.blacklists import BlacklistController from designateclient.v2.limits import LimitController from designateclient.v2.nameservers import NameServerController from designateclient.v2.pools import PoolController from designateclient.v2.quotas import QuotasController from designateclient.v2.recordsets import RecordSetController from designateclient.v2.reverse import FloatingIPController from designateclient.v2.service_statuses import ServiceStatusesController from designateclient.v2.tlds import TLDController from designateclient.v2.tsigkeys import TSIGKeysController from designateclient.v2.zones import ZoneController from designateclient.v2.zones import ZoneExportsController from designateclient.v2.zones import ZoneImportsController from designateclient.v2.zones import ZoneTransfersController from designateclient import version class DesignateAdapter(adapter.LegacyJsonAdapter): """Adapter around LegacyJsonAdapter. The user can pass a timeout keyword that will apply only to the Designate Client, in order: - timeout keyword passed to ``request()`` - timeout attribute on keystone session """ def __init__(self, *args, **kwargs): self.timeout = kwargs.pop('timeout', None) self.all_projects = kwargs.pop('all_projects', False) self.edit_managed = kwargs.pop('edit_managed', False) self.sudo_project_id = kwargs.pop('sudo_project_id', None) super(self.__class__, self).__init__(*args, **kwargs) def request(self, *args, **kwargs): kwargs.setdefault('raise_exc', False) if self.timeout is not None: kwargs.setdefault('timeout', self.timeout) kwargs.setdefault('headers', {}) if self.all_projects: kwargs['headers'].setdefault( 'X-Auth-All-Projects', str(self.all_projects) ) if self.edit_managed: kwargs['headers'].setdefault( 'X-Designate-Edit-Managed-Records', str(self.edit_managed) ) if self.sudo_project_id is not None: kwargs['headers'].setdefault( 'X-Auth-Sudo-Project-ID', self.sudo_project_id ) kwargs['headers'].setdefault( 'Content-Type', 'application/json') response, body = super(self.__class__, self).request(*args, **kwargs) # Decode is response, if possible try: response_payload = response.json() except ValueError: response_payload = {} body = response.text if response.status_code == 400: raise exceptions.BadRequest(**response_payload) elif response.status_code in (401, 403): raise exceptions.Forbidden(**response_payload) elif response.status_code == 404: raise exceptions.NotFound(**response_payload) elif response.status_code == 409: raise exceptions.Conflict(**response_payload) elif response.status_code == 413: raise exceptions.OverQuota(**response_payload) elif response.status_code >= 500: raise exceptions.Unknown(**response_payload) return response, body class Client(object): def __init__(self, region_name=None, endpoint_type='publicURL', extensions=None, service_type='dns', service_name=None, http_log_debug=False, session=None, auth=None, timeout=None, endpoint_override=None, all_projects=False, edit_managed=False, sudo_project_id=None): if session is None: raise ValueError("A session instance is required") self.session = DesignateAdapter( session, auth=auth, region_name=region_name, service_type=service_type, interface=endpoint_type.rstrip('URL'), user_agent='python-designateclient-%s' % version.version_info, version=('2'), endpoint_override=endpoint_override, timeout=timeout, all_projects=all_projects, edit_managed=edit_managed, sudo_project_id=sudo_project_id ) self.blacklists = BlacklistController(self) self.floatingips = FloatingIPController(self) self.limits = LimitController(self) self.nameservers = NameServerController(self) self.recordsets = RecordSetController(self) self.service_statuses = ServiceStatusesController(self) self.tlds = TLDController(self) self.zones = ZoneController(self) self.zone_transfers = ZoneTransfersController(self) self.zone_exports = ZoneExportsController(self) self.zone_imports = ZoneImportsController(self) self.pools = PoolController(self) self.quotas = QuotasController(self) self.tsigkeys = TSIGKeysController(self) python-designateclient-2.11.0/designateclient/v2/quotas.py0000666000175000017500000000200313366577761023677 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.v2.base import V2Controller class QuotasController(V2Controller): def list(self, project_id): return self._get('/quotas/%s' % project_id) def update(self, project_id, values): return self._patch('/quotas/%s' % project_id, data=values) def reset(self, project_id): return self._delete('/quotas/%s' % project_id) python-designateclient-2.11.0/designateclient/v2/tlds.py0000666000175000017500000000310113366577761023331 0ustar zuulzuul00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from designateclient.v2.base import V2Controller from designateclient.v2 import utils as v2_utils class TLDController(V2Controller): def create(self, name, description=None): data = { 'name': name, } if description is not None: data["description"] = description return self._post('/tlds', data=data) def list(self, criterion=None, marker=None, limit=None): url = self.build_url('/tlds', criterion, marker, limit) return self._get(url, response_key='tlds') def get(self, tld): tld = v2_utils.resolve_by_name(self.list, tld) return self._get('/tlds/%s' % tld) def update(self, tld, values): tld = v2_utils.resolve_by_name(self.list, tld) return self._patch('/tlds/%s' % tld, data=values) def delete(self, tld): tld = v2_utils.resolve_by_name(self.list, tld) return self._delete('/tlds/%s' % tld) python-designateclient-2.11.0/lower-constraints.txt0000666000175000017500000000245013366577761022564 0ustar zuulzuul00000000000000appdirs==1.3.0 asn1crypto==0.23.0 Babel==2.3.4 cffi==1.7.0 cliff==2.8.0 cmd2==0.8.0 coverage==4.0 cryptography==2.1 debtcollector==1.2.0 decorator==3.4.0 deprecation==1.0 dogpile.cache==0.6.2 dulwich==0.15.0 extras==1.0.0 fasteners==0.7.0 fixtures==3.0.0 flake8==2.5.5 future==0.16.0 hacking==0.12.0 idna==2.6 iso8601==0.1.11 jmespath==0.9.0 jsonpatch==1.16 jsonpointer==1.13 jsonschema==2.6.0 keystoneauth1==3.4.0 linecache2==1.0.0 mccabe==0.2.1 mock==2.0.0 monotonic==0.6 mox3==0.20.0 msgpack-python==0.4.0 munch==2.1.0 netaddr==0.7.18 netifaces==0.10.4 openstacksdk==0.11.2 os-client-config==1.28.0 os-service-types==1.2.0 os-testr==1.0.0 osc-lib==1.8.0 oslo.concurrency==3.25.0 oslo.config==5.2.0 oslo.context==2.19.2 oslo.i18n==3.15.3 oslo.log==3.36.0 oslo.serialization==2.18.0 oslo.utils==3.33.0 oslotest==3.2.0 paramiko==2.0.0 pbr==2.0.0 pep8==1.5.7 prettytable==0.7.2 pyasn1==0.1.8 pycparser==2.18 pyflakes==0.8.1 pyinotify==0.9.6 pyparsing==2.1.0 pyperclip==1.5.27 python-dateutil==2.5.3 python-mimeparse==1.6.0 python-subunit==1.0.0 pytz==2013.6 PyYAML==3.12 reno==2.5.0 requests==2.14.2 requests-mock==1.2.0 requestsexceptions==1.2.0 rfc3986==0.3.1 simplejson==3.5.1 six==1.10.0 stevedore==1.20.0 tempest==17.1.0 stestr==2.0.0 testtools==2.2.0 traceback2==1.4.0 unittest2==1.1.0 urllib3==1.21.1 wrapt==1.7.0 python-designateclient-2.11.0/README.rst0000666000175000017500000000300513366577761020012 0ustar zuulzuul00000000000000======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/python-designateclient.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on Python bindings to the Designate API ===================================== .. image:: https://img.shields.io/pypi/v/python-designateclient.svg :target: https://pypi.org/project/python-designateclient/ :alt: Latest Version This is a client library for Designate built on the Designate API. It provides a Python API (the ``designateclient`` module) and a command-line tool (``designate``). Development takes place via the usual OpenStack processes as outlined in the `developer guide `_. The master repository is in `Git `_. See release notes and more at ``_. * License: Apache License, Version 2.0 * `PyPi`_ - package installation * `Online Documentation`_ * `Bugs`_ - issue tracking * `Source`_ * `How to Contribute`_ .. _PyPi: https://pypi.org/project/python-designateclient .. _Online Documentation: https://docs.openstack.org/python-designateclient/latest/ .. _Bugs: https://bugs.launchpad.net/python-designateclient .. _Source: https://git.openstack.org/cgit/openstack/python-designateclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html python-designateclient-2.11.0/doc/0000775000175000017500000000000013366600247017052 5ustar zuulzuul00000000000000python-designateclient-2.11.0/doc/source/0000775000175000017500000000000013366600247020352 5ustar zuulzuul00000000000000python-designateclient-2.11.0/doc/source/index.rst0000666000175000017500000000230413366577761022232 0ustar zuulzuul00000000000000====================== python-designateclient ====================== python-designateclient provides python bindings and command line tools for both Designate v1 and v2 APIs. The :ref:`Python API bindings ` are provided by the :program:`designateclient` module. There are two separate command line interfaces to work with the two API versions: v2: the designate plugin for the :program:`openstack` command line tool. More information can be found on the :ref:`designate v2 command line tool page `. v1: the :program:`designate` command line tool. More information can be found on the :ref:`designate v1 command line tool page `. .. warning:: The V1 API was removed in Queens, and cannot be re-enabled. The :program:`designate` command line tool will no longer function on installs newer than Queens. You'll need credentials for an OpenStack cloud that implements the Designate API in order to use the client. .. toctree:: :maxdepth: 1 install/index user/index cli/index contributor/index reference/index .. rubric:: Indices and tables * :ref:`genindex` * :ref:`modindex` * :ref:`search` .. _Cloud DNS: http://www.hpcloud.com/products-services/dns python-designateclient-2.11.0/doc/source/contributor/0000775000175000017500000000000013366600247022724 5ustar zuulzuul00000000000000python-designateclient-2.11.0/doc/source/contributor/index.rst0000666000175000017500000000016113366577761024603 0ustar zuulzuul00000000000000==================== Contributors Guide ==================== .. toctree:: contributing functional-tests python-designateclient-2.11.0/doc/source/contributor/contributing.rst0000666000175000017500000000147713366577761026216 0ustar zuulzuul00000000000000Contributing ============ Code is hosted `on GitHub`_. Submit bugs to the Designate Client project on `Launchpad`_. Submit code to the openstack/python-designateclient project using `Gerrit`_. .. _on GitHub: https://github.com/openstack/python-designateclient .. _Launchpad: https://launchpad.net/python-designateclient .. _Gerrit: https://docs.openstack.org/infra/manual/developers.html#development-workflow Here's a quick summary: Install the git-review package to make life easier .. code-block:: shell-session pip install git-review Branch, work, & submit: .. code-block:: shell-session # cut a new branch, tracking master git checkout --track -b bug/id origin/master # work work work git add stuff git commit # rebase/squash to a single commit before submitting git rebase -i # submit git-review python-designateclient-2.11.0/doc/source/contributor/functional-tests.rst0000666000175000017500000000314613366577761027004 0ustar zuulzuul00000000000000================ Functional Tests ================ The functional tests invoke the client executable to see that it actually works with a running Designate. WARNING: these tests will create and delete zones, recordsets, and other resources in Designate. Installation ------------ .. code-block:: shell-session cd python-designateclient pip install python-openstackclient pip install -r requirements.txt -r test-requirements.txt pip install -e . Configuration ------------- The functional tests look for a variable ``TEMPEST_CONFIG`` which specifies a config file for the test. .. code-block:: shell-session export TEMPEST_CONFIG=tempest.conf The tests will use Keystone to grab the Designate endpoint to test against. They need at least three users (two regular users, and one admin) for all the tests to run. .. code-block:: shell-session [identity] uri = http://localhost:5000/v2.0 uri_v3 = http://localhost:5000/v3 auth_version = v2 region = RegionOne username = demo tenant_name = demo password = password domain_name = Default alt_username = alt_demo alt_tenant_name = alt_demo alt_password = password alt_domain_name = Default admin_username = admin admin_tenant_name = admin admin_password = password admin_domain_name = Default [designateclient] # the directory containing the openstack executable directory=/root/python-designateclient/.venv/bin Running the tests ----------------- The functional tests are run with tox (installed with ``pip install tox``): .. code-block:: shell-session tox -e functional python-designateclient-2.11.0/doc/source/cli/0000775000175000017500000000000013366600247021121 5ustar zuulzuul00000000000000python-designateclient-2.11.0/doc/source/cli/index.rst0000666000175000017500000005623413366577761023014 0ustar zuulzuul00000000000000.. ################################################### .. ## WARNING ###################################### .. ############## WARNING ########################## .. ########################## WARNING ############## .. ###################################### WARNING ## .. ################################################### .. ################################################### .. ## .. This file is tool-generated. Do not edit manually. .. http://docs.openstack.org/contributor-guide/ .. doc-tools/cli-reference.html .. ## .. ## WARNING ###################################### .. ############## WARNING ########################## .. ########################## WARNING ############## .. ###################################### WARNING ## .. ################################################### =========================================== DNS service (designate) command-line client =========================================== The designate client is the command-line interface (CLI) for the DNS service (designate) API and its extensions. This chapter documents :command:`designate` version ``2.6.0``. For help on a specific :command:`designate` command, enter: .. code-block:: console $ designate help COMMAND .. _designate_command_usage: designate usage ~~~~~~~~~~~~~~~ .. code-block:: console usage: designate [--version] [-v | -q] [--log-file LOG_FILE] [-h] [--debug] [--os-username OS_USERNAME] [--os-user-id OS_USER_ID] [--os-user-domain-id OS_USER_DOMAIN_ID] [--os-user-domain-name OS_USER_DOMAIN_NAME] [--os-password OS_PASSWORD] [--os-tenant-name OS_TENANT_NAME] [--os-tenant-id OS_TENANT_ID] [--os-project-name OS_PROJECT_NAME] [--os-domain-name OS_DOMAIN_NAME] [--os-domain-id OS_DOMAIN_ID] [--os-project-id OS_PROJECT_ID] [--os-project-domain-id OS_PROJECT_DOMAIN_ID] [--os-project-domain-name OS_PROJECT_DOMAIN_NAME] [--os-auth-url OS_AUTH_URL] [--os-region-name OS_REGION_NAME] [--os-token OS_TOKEN] [--os-endpoint OS_ENDPOINT] [--os-endpoint-type OS_ENDPOINT_TYPE] [--os-service-type OS_SERVICE_TYPE] [--os-cacert OS_CACERT] [--insecure] [--all-tenants] [--edit-managed] .. _designate_command_options: designate optional arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``--version`` show program's version number and exit ``-v, --verbose`` Increase verbosity of output. Can be repeated. ``-q, --quiet`` Suppress output except warnings and errors. ``--log-file LOG_FILE`` Specify a file to log output. Disabled by default. ``-h, --help`` Show help message and exit. ``--debug`` Show tracebacks on errors. ``--os-username OS_USERNAME`` Name used for authentication with the OpenStack Identity service. Defaults to ``env[OS_USERNAME]``. ``--os-user-id OS_USER_ID`` User ID used for authentication with the OpenStack Identity service. Defaults to ``env[OS_USER_ID]``. ``--os-user-domain-id OS_USER_DOMAIN_ID`` Defaults to ``env[OS_USER_DOMAIN_ID]``. ``--os-user-domain-name OS_USER_DOMAIN_NAME`` Defaults to ``env[OS_USER_DOMAIN_NAME]``. ``--os-password OS_PASSWORD`` Password used for authentication with the OpenStack Identity service. Defaults to ``env[OS_PASSWORD]``. ``--os-tenant-name OS_TENANT_NAME`` Tenant to request authorization on. Defaults to ``env[OS_TENANT_NAME]``. ``--os-tenant-id OS_TENANT_ID`` Tenant to request authorization on. Defaults to ``env[OS_TENANT_ID]``. ``--os-project-name OS_PROJECT_NAME`` Project to request authorization on. Defaults to ``env[OS_PROJECT_NAME]``. ``--os-domain-name OS_DOMAIN_NAME`` Project to request authorization on. Defaults to ``env[OS_DOMAIN_NAME]``. ``--os-domain-id OS_DOMAIN_ID`` Defaults to ``env[OS_DOMAIN_ID]``. ``--os-project-id OS_PROJECT_ID`` Project to request authorization on. Defaults to ``env[OS_PROJECT_ID]``. ``--os-project-domain-id OS_PROJECT_DOMAIN_ID`` Defaults to ``env[OS_PROJECT_DOMAIN_ID]``. ``--os-project-domain-name OS_PROJECT_DOMAIN_NAME`` Defaults to ``env[OS_PROJECT_DOMAIN_NAME]``. ``--os-auth-url OS_AUTH_URL`` Specify the Identity endpoint to use for authentication. Defaults to ``env[OS_AUTH_URL]``. ``--os-region-name OS_REGION_NAME`` Specify the region to use. Defaults to ``env[OS_REGION_NAME]``. ``--os-token OS_TOKEN`` Specify an existing token to use instead of retrieving one via authentication (e.g. with username & password). Defaults to ``env[OS_SERVICE_TOKEN]``. ``--os-endpoint OS_ENDPOINT`` Specify an endpoint to use instead of retrieving one from the service catalog (via authentication). Defaults to ``env[OS_DNS_ENDPOINT]``. ``--os-endpoint-type OS_ENDPOINT_TYPE`` Defaults to ``env[OS_ENDPOINT_TYPE]``. ``--os-service-type OS_SERVICE_TYPE`` Defaults to ``env[OS_DNS_SERVICE_TYPE]``, or 'dns'. ``--os-cacert OS_CACERT`` CA certificate bundle file. Defaults to ``env[OS_CACERT]``. ``--insecure`` Explicitly allow 'insecure' SSL requests. ``--all-tenants`` Allows to list all domains from all tenants. ``--edit-managed`` Allows to edit records that are marked as managed. .. _designate_diagnostics-ping: designate diagnostics-ping -------------------------- .. code-block:: console usage: designate diagnostics-ping [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] --service SERVICE --host HOST Ping a service on a given host **Optional arguments:** ``-h, --help`` show this help message and exit ``--service SERVICE`` Service name (e.g. central) ``--host HOST`` Hostname .. _designate_domain-create: designate domain-create ----------------------- .. code-block:: console usage: designate domain-create [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] --name NAME --email EMAIL [--ttl TTL] [--description DESCRIPTION] Create Domain **Optional arguments:** ``-h, --help`` show this help message and exit ``--name NAME`` Domain name. ``--email EMAIL`` Domain email. ``--ttl TTL`` Time to live (seconds). ``--description DESCRIPTION`` Description. .. _designate_domain-delete: designate domain-delete ----------------------- .. code-block:: console usage: designate domain-delete [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] id Delete Domain **Positional arguments:** ``id`` Domain ID or name. **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_domain-get: designate domain-get -------------------- .. code-block:: console usage: designate domain-get [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] id Get Domain **Positional arguments:** ``id`` Domain ID or name. **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_domain-list: designate domain-list --------------------- .. code-block:: console usage: designate domain-list [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] List Domains **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_domain-servers-list: designate domain-servers-list ----------------------------- .. code-block:: console usage: designate domain-servers-list [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] id List Domain Servers **Positional arguments:** ``id`` Domain ID or name. **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_domain-update: designate domain-update ----------------------- .. code-block:: console usage: designate domain-update [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] [--name NAME] [--email EMAIL] [--ttl TTL] [--description DESCRIPTION | --no-description] id Update Domain **Positional arguments:** ``id`` Domain ID or name. **Optional arguments:** ``-h, --help`` show this help message and exit ``--name NAME`` Domain name. ``--email EMAIL`` Domain email. ``--ttl TTL`` Time to live (seconds). ``--description DESCRIPTION`` Description. ``--no-description`` .. _designate_quota-get: designate quota-get ------------------- .. code-block:: console usage: designate quota-get [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] tenant_id Get Quota **Positional arguments:** ``tenant_id`` Tenant ID **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_quota-reset: designate quota-reset --------------------- .. code-block:: console usage: designate quota-reset [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] tenant_id Reset Quota **Positional arguments:** ``tenant_id`` Tenant ID. **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_quota-update: designate quota-update ---------------------- .. code-block:: console usage: designate quota-update [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] [--domains DOMAINS] [--domain-recordsets DOMAIN_RECORDSETS] [--recordset-records RECORDSET_RECORDS] [--domain-records DOMAIN_RECORDS] [--api-export-size API_EXPORT_SIZE] tenant_id Update Quota **Positional arguments:** ``tenant_id`` Tenant ID. **Optional arguments:** ``-h, --help`` show this help message and exit ``--domains DOMAINS`` Allowed domains. ``--domain-recordsets DOMAIN_RECORDSETS`` Allowed domain records. ``--recordset-records RECORDSET_RECORDS`` Allowed recordset records. ``--domain-records DOMAIN_RECORDS`` Allowed domain records. ``--api-export-size API_EXPORT_SIZE`` Allowed zone export recordsets. .. _designate_record-create: designate record-create ----------------------- .. code-block:: console usage: designate record-create [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] --name NAME --type TYPE --data DATA [--ttl TTL] [--priority PRIORITY] [--description DESCRIPTION] domain_id Create Record **Positional arguments:** ``domain_id`` Domain ID or name. **Optional arguments:** ``-h, --help`` show this help message and exit ``--name NAME`` Record (relative|absolute) name. ``--type TYPE`` Record type. ``--data DATA`` Record data. ``--ttl TTL`` Record TTL. ``--priority PRIORITY`` Record priority. ``--description DESCRIPTION`` Description. .. _designate_record-delete: designate record-delete ----------------------- .. code-block:: console usage: designate record-delete [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] domain_id id Delete Record **Positional arguments:** ``domain_id`` Domain ID or name. ``id`` Record ID. **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_record-get: designate record-get -------------------- .. code-block:: console usage: designate record-get [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] domain_id id Get Record **Positional arguments:** ``domain_id`` Domain ID or name. ``id`` Record ID. **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_record-list: designate record-list --------------------- .. code-block:: console usage: designate record-list [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] domain_id List Records **Positional arguments:** ``domain_id`` Domain ID or name. **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_record-update: designate record-update ----------------------- .. code-block:: console usage: designate record-update [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] [--name NAME] [--type TYPE] [--data DATA] [--description DESCRIPTION | --no-description] [--ttl TTL | --no-ttl] [--priority PRIORITY | --no-priority] domain_id id Update Record **Positional arguments:** ``domain_id`` Domain ID or name. ``id`` Record ID. **Optional arguments:** ``-h, --help`` show this help message and exit ``--name NAME`` Record name. ``--type TYPE`` Record type. ``--data DATA`` Record data. ``--description DESCRIPTION`` Description. ``--no-description`` ``--ttl TTL`` Record time to live (seconds). ``--no-ttl`` ``--priority PRIORITY`` Record priority. ``--no-priority`` .. _designate_report-count-all: designate report-count-all -------------------------- .. code-block:: console usage: designate report-count-all [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] Get count totals for all tenants, domains and records **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_report-count-domains: designate report-count-domains ------------------------------ .. code-block:: console usage: designate report-count-domains [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] Get counts for total domains **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_report-count-records: designate report-count-records ------------------------------ .. code-block:: console usage: designate report-count-records [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] Get counts for total records **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_report-count-tenants: designate report-count-tenants ------------------------------ .. code-block:: console usage: designate report-count-tenants [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] Get counts for total tenants **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_report-tenant-domains: designate report-tenant-domains ------------------------------- .. code-block:: console usage: designate report-tenant-domains [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] --report-tenant-id REPORT_TENANT_ID Get a list of domains for given tenant **Optional arguments:** ``-h, --help`` show this help message and exit ``--report-tenant-id REPORT_TENANT_ID`` The tenant_id being reported on. .. _designate_report-tenants-all: designate report-tenants-all ---------------------------- .. code-block:: console usage: designate report-tenants-all [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] Get list of tenants and domain count for each **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_server-create: designate server-create ----------------------- .. code-block:: console usage: designate server-create [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] --name NAME Create Server **Optional arguments:** ``-h, --help`` show this help message and exit ``--name NAME`` Server name. .. _designate_server-delete: designate server-delete ----------------------- .. code-block:: console usage: designate server-delete [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] id Delete Server **Positional arguments:** ``id`` Server ID. **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_server-get: designate server-get -------------------- .. code-block:: console usage: designate server-get [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] id Get Server **Positional arguments:** ``id`` Server ID. **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_server-list: designate server-list --------------------- .. code-block:: console usage: designate server-list [-h] [-f {csv,html,json,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--quote {all,minimal,none,nonnumeric}] List Servers **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_server-update: designate server-update ----------------------- .. code-block:: console usage: designate server-update [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] [--name NAME] id Update Server **Positional arguments:** ``id`` Server ID. **Optional arguments:** ``-h, --help`` show this help message and exit ``--name NAME`` Server name. .. _designate_sync-all: designate sync-all ------------------ .. code-block:: console usage: designate sync-all [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] Sync Everything **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_sync-domain: designate sync-domain --------------------- .. code-block:: console usage: designate sync-domain [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] domain_id Sync a single Domain **Positional arguments:** ``domain_id`` Domain ID **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_sync-record: designate sync-record --------------------- .. code-block:: console usage: designate sync-record [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] domain_id record_id Sync a single Record **Positional arguments:** ``domain_id`` Domain ID ``record_id`` Record ID **Optional arguments:** ``-h, --help`` show this help message and exit .. _designate_touch-domain: designate touch-domain ---------------------- .. code-block:: console usage: designate touch-domain [-h] [-f {html,json,shell,table,value,yaml}] [-c COLUMN] [--max-width ] [--print-empty] [--noindent] [--prefix PREFIX] domain_id Touch a single Domain **Positional arguments:** ``domain_id`` Domain ID **Optional arguments:** ``-h, --help`` show this help message and exit python-designateclient-2.11.0/doc/source/reference/0000775000175000017500000000000013366600247022310 5ustar zuulzuul00000000000000python-designateclient-2.11.0/doc/source/reference/index.rst0000666000175000017500000000021013366577761024162 0ustar zuulzuul00000000000000================================== python-designateclient Reference ================================== .. toctree:: api/autoindex python-designateclient-2.11.0/doc/source/install/0000775000175000017500000000000013366600247022020 5ustar zuulzuul00000000000000python-designateclient-2.11.0/doc/source/install/index.rst0000666000175000017500000000272513366577761023707 0ustar zuulzuul00000000000000============ Installation ============ Install the client from PyPI ---------------------------- The :program:`python-designateclient` package is published on `PyPI`_ and so can be installed using the pip tool, which will manage installing all python dependencies: .. code-block:: shell-session pip install python-designateclient *Warning: the packages on PyPI may lag behind the git repo in functionality.* Setup the client from source ---------------------------- If you want the latest version, straight from github: .. code-block:: shell-session git clone git@github.com:openstack/python-designateclient.git cd python-designateclient virtualenv .venv . .venv/bin/activate pip install -r requirements.txt -r test-requirements.txt python setup.py install Setup the client in development mode ------------------------------------ Installing in development mode allows your to make changes to the source code & test directly without having to re-run the "python setup.py install" step. You can find out more about `Development Mode`_ .. code-block:: shell-session git clone git@github.com:openstack/python-designateclient.git cd python-designateclient virtualenv .venv . .venv/bin/activate pip install -r requirements.txt -r test-requirements.txt python setup.py develop .. _Development Mode: https://setuptools.readthedocs.io/en/latest/setuptools.html#development-mode .. _PyPI: https://pypi.org/project/python-designateclient/ python-designateclient-2.11.0/doc/source/conf.py0000666000175000017500000000361613366577761021677 0ustar zuulzuul00000000000000# -*- coding: utf-8 -*- # # designateclient documentation build configuration file # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'openstackdocstheme'] # openstackdocstheme options repository_name = 'openstack/python-designateclient' bug_project = 'python-designateclient' bug_tag = '' html_last_updated_fmt = '%Y-%m-%d %H:%M' html_theme = 'openstackdocs' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = u'designateclient' copyright = u'2012, Managed I.T. 2013-2014, Hewlett-Packard Development Company, L.P.' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. from designateclient.version import version_info as designateclient_version version = designateclient_version.canonical_version_string() # The full version, including alpha/beta/rc tags. release = designateclient_version.version_string_with_vcs() # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. modindex_common_prefix = ['designateclient'] # -- Options for HTML output --------------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'designateclientdoc' python-designateclient-2.11.0/doc/source/user/0000775000175000017500000000000013366600247021330 5ustar zuulzuul00000000000000python-designateclient-2.11.0/doc/source/user/shell.rst0000666000175000017500000002702513366577761023217 0ustar zuulzuul00000000000000.. _shell: ========================================================= Designate Command Line Tool (compatible with v1 API only) ========================================================= .. warning:: This page refers to command that use the V1 API, which is currently disabled, and will be removed in a future release The python-designateclient package comes with a command line tool (installed as :program:`designate`), this can be used to access a Designate API without having to manipulate JSON by hand, it can also produce the output in a variety of formats (JSON, CSV) and allow you to select columns to be displayed. Credentials ----------- As with any OpenStack utility, :program:`designate` requires certain information to talk to the REST API, username, password, auth url (from where the other required endpoints are retrieved once you are authenticated). To provide your access credentials (username, password, tenant name or tenant id) you can pass them on the command line with the ``--os-username``, ``--os-password``, ``--os-tenant-name`` or ``--os-tenant-id`` params, but it's easier to just set them as environment variables:: export OS_USERNAME=openstack export OS_PASSWORD=yadayada export OS_TENANT_NAME=myproject export OS_TENANT_ID=123456789 You will also need to define the authentication url with ``--os-auth-url`` or set is as an environment variable as well:: export OS_AUTH_URL=https://example.com:5000/v2.0/ Since Keystone can return multiple regions in the Service Catalog, you can specify the one you want with ``--os-region-name`` (or ``export OS_REGION_NAME``). It defaults to the first in the list returned. Using the command line tool --------------------------- With enough details now in the environment, you can use the designate client to create a domain and populate it with some records: .. code-block:: shell-session $ designate domain-create --name example.com. --email admin@example.com +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | description | None | | created_at | 2013-09-19T11:45:25.295355 | | updated_at | None | | email | admin@example.com | | ttl | 3600 | | serial | 1379591125 | | id | eacbe2a5-95f1-4a9f-89f5-b9c58009b163 | | name | example.com. | +-------------+--------------------------------------+ Now that the domain has been created, we can start adding records. You'll note that the name (www.example.com) has a trailing ``.``, as per the DNS standard, we didn't set a TTL and we had to specify the parent zone/domain by domain_id ``eacbe2a5-95f1-4a9f-89f5-b9c58009b163``. .. code-block:: shell-session $ designate record-create eacbe2a5-95f1-4a9f-89f5-b9c58009b163 --name www.example.com. --type A --data 1.2.3.4 +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | name | www.example.com. | | data | 1.2.3.4 | | created_at | 2013-09-19T13:44:42.295428 | | updated_at | None | | id | 147f6082-8466-4951-8d13-37a10e92b11e | | priority | None | | ttl | None | | type | A | | domain_id | eacbe2a5-95f1-4a9f-89f5-b9c58009b163 | | description | None | +-------------+--------------------------------------+ subcommands ----------- We've already seen the ``domain-create`` and ``record-create`` subcommands, here the full list of subcommands: ======================= ====================================================== =============== subcommand Notes Admin Required ======================= ====================================================== =============== complete print bash completion command diagnostics-ping Ping a service on a given host domain-create Create Domain domain-delete Delete Domain domain-get Get Domain domain-list List Domains domain-servers-list List Domain Servers domain-update Update Domain help print detailed help for another command quota-get Get Quota quota-reset Reset Quota quota-update Update Quota record-create Create Record record-delete Delete Record record-get Get Record record-list List Records record-update Update Record report-count-all Get count totals for all tenants, domains and records report-count-domains Get counts for total domains report-count-records Get counts for total records report-count-tenants Get counts for total tenants report-tenant-domains Get a list of domains for given tenant report-tenants-all Get list of tenants and domain count for each server-create Create Server server-delete Delete Server server-get Get Server server-list List Servers server-update Update Server sync-all Sync Everything sync-domain Sync a single Domain sync-record Sync a single Record touch-domain Touch a single Domain ======================= ====================================================== =============== Builtin designate documentation ------------------------------- You'll find complete documentation on the shell by running ``designate --help``: usage: designate [--version] [-v] [--log-file LOG_FILE] [-q] [-h] [--debug] [--os-username OS_USERNAME] [--os-user-id OS_USER_ID] [--os-user-domain-id OS_USER_DOMAIN_ID] [--os-user-domain-name OS_USER_DOMAIN_NAME] [--os-password OS_PASSWORD] [--os-tenant-name OS_TENANT_NAME] [--os-tenant-id OS_TENANT_ID] [--os-project-name OS_PROJECT_NAME] [--os-domain-name OS_DOMAIN_NAME] [--os-domain-id OS_DOMAIN_ID] [--os-project-id OS_PROJECT_ID] [--os-project-domain-id OS_PROJECT_DOMAIN_ID] [--os-project-domain-name OS_PROJECT_DOMAIN_NAME] [--os-auth-url OS_AUTH_URL] [--os-region-name OS_REGION_NAME] [--os-token OS_TOKEN] [--os-endpoint OS_ENDPOINT] [--os-endpoint-type OS_ENDPOINT_TYPE] [--os-service-type OS_SERVICE_TYPE] [--os-cacert OS_CACERT] [--insecure] [--all-tenants] [--edit-managed] Designate Client optional arguments: --version show program's version number and exit -v, --verbose Increase verbosity of output. Can be repeated. --log-file LOG_FILE Specify a file to log output. Disabled by default. -q, --quiet Suppress output except warnings and errors. -h, --help Show this help message and exit. --debug Show tracebacks on errors. --os-username OS_USERNAME Name used for authentication with the OpenStack Identity service. Defaults to env[OS_USERNAME]. --os-user-id OS_USER_ID User ID used for authentication with the OpenStack Identity service. Defaults to env[OS_USER_ID]. --os-user-domain-id OS_USER_DOMAIN_ID Defaults to env[OS_USER_DOMAIN_ID]. --os-user-domain-name OS_USER_DOMAIN_NAME Defaults to env[OS_USER_DOMAIN_NAME]. --os-password OS_PASSWORD Password used for authentication with the OpenStack Identity service. Defaults to env[OS_PASSWORD]. --os-tenant-name OS_TENANT_NAME Tenant to request authorization on. Defaults to env[OS_TENANT_NAME]. --os-tenant-id OS_TENANT_ID Tenant to request authorization on. Defaults to env[OS_TENANT_ID]. --os-project-name OS_PROJECT_NAME Project to request authorization on. Defaults to env[OS_PROJECT_NAME]. --os-domain-name OS_DOMAIN_NAME Project to request authorization on. Defaults to env[OS_DOMAIN_NAME]. --os-domain-id OS_DOMAIN_ID Defaults to env[OS_DOMAIN_ID]. --os-project-id OS_PROJECT_ID Project to request authorization on. Defaults to env[OS_PROJECT_ID]. --os-project-domain-id OS_PROJECT_DOMAIN_ID Defaults to env[OS_PROJECT_DOMAIN_ID]. --os-project-domain-name OS_PROJECT_DOMAIN_NAME Defaults to env[OS_PROJECT_DOMAIN_NAME]. --os-auth-url OS_AUTH_URL Specify the Identity endpoint to use for authentication. Defaults to env[OS_AUTH_URL]. --os-region-name OS_REGION_NAME Specify the region to use. Defaults to env[OS_REGION_NAME]. --os-token OS_TOKEN Specify an existing token to use instead of retrieving one via authentication (e.g. with username & password). Defaults to env[OS_SERVICE_TOKEN]. --os-endpoint OS_ENDPOINT Specify an endpoint to use instead of retrieving one from the service catalog (via authentication). Defaults to env[OS_DNS_ENDPOINT]. --os-endpoint-type OS_ENDPOINT_TYPE Defaults to env[OS_ENDPOINT_TYPE]. --os-service-type OS_SERVICE_TYPE Defaults to env[OS_DNS_SERVICE_TYPE], or 'dns'. --os-cacert OS_CACERT CA certificate bundle file. Defaults to env[OS_CACERT]. --insecure Explicitly allow 'insecure' SSL requests. --all-tenants Allows to list all domains from all tenants. --edit-managed Allows to edit records that are marked as managed. Commands: complete print bash completion command diagnostics-ping Ping a service on a given host domain-create Create Domain domain-delete Delete Domain domain-get Get Domain domain-list List Domains domain-servers-list List Domain Servers domain-update Update Domain help print detailed help for another command quota-get Get Quota quota-reset Reset Quota quota-update Update Quota record-create Create Record record-delete Delete Record record-get Get Record record-list List Records record-update Update Record report-count-all Get count totals for all tenants, domains and records report-count-domains Get counts for total domains report-count-records Get counts for total records report-count-tenants Get counts for total tenants report-tenant-domains Get a list of domains for given tenant report-tenants-all Get list of tenants and domain count for each server-create Create Server server-delete Delete Server server-get Get Server server-list List Servers server-update Update Server sync-all Sync Everything sync-domain Sync a single Domain sync-record Sync a single Record touch-domain Touch a single Domain python-designateclient-2.11.0/doc/source/user/index.rst0000666000175000017500000000023613366577761023212 0ustar zuulzuul00000000000000============================== Using python-designateclient ============================== .. toctree:: bindings shell-v2 shell shell-examples python-designateclient-2.11.0/doc/source/user/shell-examples.rst0000666000175000017500000001733713366577761025040 0ustar zuulzuul00000000000000==================================== Designate Command Line Tool Examples ==================================== .. warning:: This page refers to command that use the V1 API, which is currently disabled, and will be removed in a future release Using the client against your dev environment --------------------------------------------- Typically the designate client talks to Keystone (or a Keystone like service) via the OS_AUTH_URL setting & retrives the designate endpoint from the returned service catalog. Using ``--os-endpoint`` or ``OS_ENDPOINT`` you can specify the end point directly, this is useful if you want to point the client at a test environment that's running without a full Keystone service. .. code-block:: shell-session $ designate --os-endpoint http://127.0.0.1:9001/v1 server-create --name ns.example.com. +------------+--------------------------------------+ | Field | Value | +------------+--------------------------------------+ | id | 3dee78df-c6b8-4fbd-8e89-3186c1a4734f | | created_at | 2015-11-04T08:47:12.000000 | | updated_at | None | | name | ns.example.com. | +------------+--------------------------------------+ $ designate --os-endpoint http://127.0.0.1:9001/v1 domain-create --name example.net. --email me@example.org +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | description | None | | created_at | 2015-11-04T08:49:53.000000 | | updated_at | None | | email | me@example.org | | ttl | 3600 | | serial | 1446626993 | | id | f98c3d91-f514-4956-a955-20eefb413a64 | | name | example.net. | +-------------+--------------------------------------+ $ designate --os-endpoint http://127.0.0.1:9001/v1 record-create --name myhost.example.net. --type A --data 1.2.3.4 f98c3d91-f514-4956-a955-20eefb413a64 (domain_id) +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | description | None | | type | A | | created_at | 2015-11-04T08:52:41.000000 | | updated_at | None | | domain_id | f98c3d91-f514-4956-a955-20eefb413a64 | | priority | None | | ttl | None | | data | 1.2.3.4 | | id | b5a74471-8062-4395-be70-968805a0d832 | | name | myhost.example.net. | +-------------+--------------------------------------+ $ designate domain-list +--------------------------------------+--------------+------------+ | id | name | serial | +--------------------------------------+--------------+------------+ | 88c14ecf-b034-424c-b081-ca42494dcdf9 | example.com. | 1462372104 | +--------------------------------------+--------------+------------+ $ designate domain-update --email example@example.com 88c14ecf-b034-424c-b081-ca42494dcdf9 (domain_id) +-------------+---------------------------------------+ | Field | Value | +-------------+---------------------------------------+ | description | None | | created_at | 2016-05-04T14:28:24.000000 | | updated_at | 2016-05-04T14:29:48.000000 | | email | example@example.com | | ttl | 3600 | | serial | 1462372188 | | id | 88c14ecf-b034-424c-b081-ca42494dcdf9 | | name | example.com. | +-------------+---------------------------------------+ $ designate domain-delete 88c14ecf-b034-424c-b081-ca42494dcdf9 (domain_id) $ designate record-list 66584cdd-f7a6-4f0e-acf0-3dd5ad04830d (domain_id) +--------------------------------------+------+-----------------------+-----------------------------------------------------------------+ | id | type | name | data | +--------------------------------------+------+-----------------------+-----------------------------------------------------------------+ | fdfab9c3-51c0-42b9-b500-7779ef917915 | SOA | example.com. | ns1.example.org. pr8721.att.com. 1462372695 3600 600 86400 3600 | | 242a16e8-8455-4b4d-af7f-45de1074aa04 | NS | example.com. | xyz.com. | | 8dc14df7-3651-49df-8c83-0d71954c6152 | NS | example.com. | ns1.example.org. | | 7e80531d-bd65-49bc-a316-a6a06cd7fe26 | A | example1.example.com. | 198.51.100.1 | +--------------------------------------+------+-----------------------+-----------------------------------------------------------------+ $ designate record-update --name example1.example.com. --type A --data 198.5.100.2 --ttl 3600 66584cdd-f7a6-4f0e-acf0-3dd5ad04830d (domain-id) 7e80531d-bd65-49bc-a316-a6a06cd7fe26 (record_id) +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | description | None | | type | A | | created_at | 2016-05-04T14:38:15.000000 | | updated_at | 2016-05-04T16:12:05.000000 | | domain_id | 66584cdd-f7a6-4f0e-acf0-3dd5ad04830d | | priority | None | | ttl | 3600 | | data | 198.5.100.2 | | id | 7e80531d-bd65-49bc-a316-a6a06cd7fe26 | | name | example1.example.com. | +-------------+--------------------------------------+ $ designate record-delete 66584cdd-f7a6-4f0e-acf0-3dd5ad04830d (domain-id) 7e80531d-bd65-49bc-a316-a6a06cd7fe26 (record_id) $ designate quota-get 70a4596c9974429db5fb6fe240ab87b9 (tenant_id) +-------------------+-------+ | Field | Value | +-------------------+-------+ | domains | 10 | | domain_recordsets | 500 | | recordset_records | 20 | | domain_records | 500 | +-------------------+-------+ $ designate quota-update --domains 50 --domain-recordsets 1000 --recordset-records 40 --domain-records 1000 70a4596c9974429db5fb6fe240ab87b9 (tenant_id) +-------------------+-------+ | Field | Value | +-------------------+-------+ | domains | 50 | | domain_recordsets | 1000 | | recordset_records | 40 | | domain_records | 1000 | +-------------------+-------+ $ designate quota-get 70a4596c9974429db5fb6fe240ab87b9 (tenant_id) +-------------------+-------+ | Field | Value | +-------------------+-------+ | domains | 10 | | domain_recordsets | 500 | | recordset_records | 20 | | domain_records | 500 | +-------------------+-------+ python-designateclient-2.11.0/doc/source/user/bindings.rst0000666000175000017500000003147113366577761023705 0ustar zuulzuul00000000000000.. _bindings: =========================== Python Bindings - v1 and v2 =========================== The python-designateclient package comes with python bindings for both versions of the Designate API: v1 and v2. These can be used to interact with the Designate API from any python program. Introduction - Bindings v2 ========================== To view examples of usage please checkout the *doc/examples* folder, basic usage is: .. code-block:: python #!/usr/bin/env python from designateclient.v2 import client from designateclient import shell from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session auth = generic.Password( auth_url=shell.env('OS_AUTH_URL'), username=shell.env('OS_USERNAME'), password=shell.env('OS_PASSWORD'), project_name=shell.env('OS_PROJECT_NAME'), project_domain_id='default', user_domain_id='default') session = keystone_session.Session(auth=auth) client = client.Client(session=session) zone = client.zones.create('i.io.', email='i@i.io') rs = client.recordsets.create(zone['id'], 'www', 'A', ['10.0.0.1']) Introduction ============ Below is a simple example of how to instantiate and perform basic tasks using the bindings. .. code-block:: python #!/usr/bin/env python from __future__ import print_function from designateclient.v1 import Client # Create an instance of the client, providing the necessary credentials client = Client( auth_url="https://example.com:5000/v3/", username="openstack", password="yadayada", project_name="myproject", project_domain_id='default', user_domain_id='default') # Fetch a list of the domains this user/tenant has access to domains = client.domains.list() # Iterate the list, printing some useful information for domain in domains: print("Domain ID: %s, Name: %s" % (domain.id, domain.name)) And the output this program might produce: .. code-block:: console $ python /tmp/example.py Domain ID: 467f97b4-f074-4839-ae85-1a61fccfb83d, Name: example-one.com. Domain ID: 6d3bf479-8a93-47ae-8c65-3dff8dba1b0d, Name: example-two.com. Authentication ============== Designate supports either Keystone authentication, or no authentication at all. Keystone Authentication ----------------------- Below is a sample of standard authentication with keystone using keystoneauth Sessions. For more information on keystoneauth API, see `Using Sessions`_. .. _Using Sessions: https://docs.openstack.org/keystoneauth/latest/using-sessions.html .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session # Create an authentication plugin providing the necessary credentials auth = generic.Password( auth_url="https://example.com:5000/v3/", username="openstack", password="yadayada", project_name="myproject", project_domain_id='default', user_domain_id='default' ) session = keystone_session.Session(auth=auth) # Create an instance of the client, providing a keystoneauth Session client = Client(session=session) Below is a sample of standard authentication with keystone, but also explicitly providing the endpoint to use: .. note:: This is useful when a development Designate instances authenticates against a production Keystone. .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session # Create an authentication plugin providing the necessary credentials auth = generic.Password( auth_url="https://example.com:5000/v3/", username="openstack", password="yadayada", project_name="myproject", project_domain_id='default', user_domain_id='default') session = keystone_session.Session(auth=auth) # Create an instance of the client, providing a keystoneauth Session client = Client( session=session, endpoint="https://127.0.0.1:9001/v1/") No Authentication ----------------- Below is a sample of interaction with a non authenticated designate: .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client, providing the endpoint directly client = Client( endpoint="https://127.0.0.1:9001/v1/" ) Working with Domains ==================== The Domain Object ----------------- Object Properties: ======================= ======================================================= Property Description ======================= ======================================================= id Domain ID name Domain Name (e.g. example.com.) email Domain Responsible Person Email (e.g. fred@example.com) ttl Default TTL for records serial Domain Server Number created_at Date and time this domain was created at updated_at Date and time this domain was last updated description Domain Description ======================= ======================================================= Listing Domains --------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) # List All Domains domains = client.domains.list() Fetching a Domain by ID ----------------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) domain_id = 'fb505f10-25df-11e3-8224-0800200c9a66' # Fetch the domain domain = client.domains.get(domain_id) Creating a Domain ----------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client from designateclient.v1.domains import Domain # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) # Create a new Domain object domain = Domain(name="example.com.", email="fred@example.com") # Send the Create Domain API call domain = client.domains.create(domain) Updating a Domain ----------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) domain_id = 'fb505f10-25df-11e3-8224-0800200c9a66' # Fetch the domain domain = client.domains.get(domain_id) # Update a value on the Domain domain.ttl = 300 # Send the Update Domain API call domain = client.domains.update(domain) Deleting a Domain ----------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) domain_id = 'fb505f10-25df-11e3-8224-0800200c9a66' # Fetch the domain domains = client.domains.delete(domain_id) Working with Records ==================== The Record Object ----------------- Object Properties: ======================= ======================================================= Property Description ======================= ======================================================= id Record ID domain_id Domain ID name Record Name (e.g. example.com.) type Record Type (e.g. A, AAAA, CNAME, MX, SRV etc) data Record Data (e.g. 127.0.0.1) priority Rercord Priority (Valid only for MX and SRV records) ttl Record TTL created_at Date and time this record was created at updated_at Date and time this record was last updated description Record Description ======================= ======================================================= Listing Records --------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) domain_id = 'fb505f10-25df-11e3-8224-0800200c9a66' # List All Records records = client.records.list(domain_id) Fetching a Record by ID ----------------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) domain_id = 'fb505f10-25df-11e3-8224-0800200c9a66' record_id = 'bd3e8520-25e0-11e3-8224-0800200c9a66' # Fetch the record records = client.records.get(domain_id, record_id) Creating a Record ----------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client from designateclient.v1.records import Record # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) domain_id = 'fb505f10-25df-11e3-8224-0800200c9a66' # Create a new Record object record = Record(name="www.example.com.", type="A", data="127.0.0.1") # Send the Create Record API call record = client.records.create(domain_id, record) Updating a Record ----------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) domain_id = 'fb505f10-25df-11e3-8224-0800200c9a66' record_id = 'bd3e8520-25e0-11e3-8224-0800200c9a66' # Fetch the record record = client.records.get(record_id) # Update a value on the Record record.ttl = 300 # Send the Update Record API call record = client.records.update(domain_id, record) Deleting a Record ----------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) domain_id = 'fb505f10-25df-11e3-8224-0800200c9a66' record_id = 'bd3e8520-25e0-11e3-8224-0800200c9a66' # Fetch the record records = client.records.delete(domain_id, record_id) Working with Servers ==================== The Server Object ----------------- Object Properties: ======================= ======================================================= Property Description ======================= ======================================================= id Server ID name Server Name (e.g. example.com.) created_at Date and time this server was created at updated_at Date and time this server was last updated ======================= ======================================================= Listing Servers --------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) # List All Servers servers = client.servers.list() Fetching a Server by ID ----------------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) server_id = 'fb505f10-25df-11e3-8224-0800200c9a66' # Fetch the server server = client.servers.get(server_id) Creating a Server ----------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client from designateclient.v1.servers import Server # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) # Create a new Server object server = Server(name="ns1.example.com.") # Send the Create Server API call server = client.servers.create(server) Updating a Server ----------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) server_id = 'fb505f10-25df-11e3-8224-0800200c9a66' # Fetch the server server = client.servers.get(server_id) # Update a value on the Server server.name = "ns2.example.com" # Send the Update Server API call server = client.servers.update(server) Deleting a Server ----------------- .. code-block:: python #!/usr/bin/env python from designateclient.v1 import Client # Create an instance of the client client = Client( endpoint="https://127.0.0.1:9001/v1/" ) server_id = 'fb505f10-25df-11e3-8224-0800200c9a66' # Fetch the server servers = client.servers.delete(server_id) python-designateclient-2.11.0/doc/source/user/shell-v2.rst0000666000175000017500000005575213366577761023554 0ustar zuulzuul00000000000000.. _shell-v2: =========================== OpenStack CLI (v2 API only) =========================== The python-designateclient package comes with a plugin for the openstack command line tool (installed as :program:`openstack`). This can be used to access a Designate API without having to manipulate JSON by hand, it can also produce the output in a variety of formats (JSON, CSV) and allow you to select columns to be displayed. Installation ------------ Both *python-openstackclient* and *python-designateclient* must be installed: :: $ pip install python-openstackclient python-designateclient Configuration ------------- :program:`openstack` requires certain information to talk to the REST API. An in-depth explanation is covered in the `OpenStack Client configuration documentation`_. To get started, all you usually need are the following variables: :: OS_AUTH_VERSION=3 OS_IDENTITY_API_VERSION=3 OS_AUTH_URL=http://127.0.0.1:5000/v3 OS_PROJECT_NAME=demo OS_USERNAME=demo OS_TENANT_NAME=demo OS_PASSWORD=password Using the Command Line Tool --------------------------- With enough details now in the environment, you can use the :program:`openstack` to create a zone and populate it with some records: .. code-block:: shell-session $ openstack zone create --email admin@example.com example.com. +----------------+--------------------------------------+ | Field | Value | +----------------+--------------------------------------+ | action | CREATE | | created_at | 2016-04-19T17:44:04.000000 | | description | None | | email | admin@example.com | | id | 388814ef-3c5d-415e-a866-5b1d13d78dae | | masters | | | name | example.com. | | pool_id | 794ccc2c-d751-44fe-b57f-8894c9f5c842 | | project_id | 123456 | | serial | 1461087844 | | status | PENDING | | transferred_at | None | | ttl | 3600 | | type | PRIMARY | | updated_at | None | | version | 1 | +----------------+--------------------------------------+ Now that the zone has been created, we can start adding records. You'll note that the zone name (example.com) has a trailing ``.``, as per the DNS standard, and we didn't set a TTL. .. code-block:: shell-session $ openstack recordset create --type A --records 192.0.2.20 example.com. www +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | action | CREATE | | created_at | 2016-04-19T17:51:12.000000 | | description | None | | id | 180d3574-3c29-4ea2-b6ff-df904bd3f126 | | name | www.example.com. | | records | 192.0.2.20 | | status | PENDING | | ttl | None | | type | A | | updated_at | None | | version | 1 | | zone_id | 388814ef-3c5d-415e-a866-5b1d13d78dae | +-------------+--------------------------------------+ Designate-specific Subcommands ------------------------------ Aside from the ``zone create`` and ``recordset create`` subcommands, this is the full list of subcommands that enable Designate V2 support: ============================ ====================================================== =============== subcommand Notes Admin Required ============================ ====================================================== =============== zone create Create new zone zone list List zones zone show Show zone details zone set Set zone properties zone delete Delete zone recordset create Create new recordset recordset list List recordsets recordset list all List all recordsets in all zones recordset show Show recordset details recordset set Set recordset properties recordset delete Delete recordset ptr record list List floatingip ptr records ptr record show Show floatingip ptr record details ptr record set Set floatingip ptr record ptr record unset Unset floatingip ptr record zone export create Export a Zone zone export list List Zone Exports zone export show Show a Zone Export zone export delete Delete a Zone Export zone export showfile Show the zone file for the Zone Export zone import create Import a Zone from a file on the filesystem zone import list List Zone Imports zone import show Show a Zone Import zone import delete Delete a Zone Import zone transfer request create Create new zone transfer request zone transfer request list List Zone Transfer Requests zone transfer request show Show Zone Transfer Request Details zone transfer request set Set a Zone Transfer Request zone transfer request delete Delete a Zone Transfer Request zone transfer accept request Accept a Zone Transfer Request zone transfer accept list List Zone Transfer Accepts zone transfer accept show Show Zone Transfer Accept zone abandon Abandon a zone Yes zone axfr AXFR a zone zone blacklist create Create new blacklist Yes zone blacklist list List blacklists Yes zone blacklist show Show blacklist details Yes zone blacklist set Set blacklist properties Yes zone blacklist delete Delete blacklist Yes tld create Create new tld Yes tld list List tlds Yes tld show Show tld details Yes tld set Set tld properties Yes tld delete Delete tld Yes ============================ ====================================================== =============== Built-in Designate Documentation -------------------------------- You'll find complete documentation on the shell by running: ``openstack --help`` For a specific command, you can execute: ``openstack subcommand help`` Examples -------- Because command output would make this document long, much of it will be omitted from some examples. Working with Zones '''''''''''''''''' Create a zone with the following command: .. code-block:: shell-session $ openstack zone create --email admin@example.com example.com. +----------------+--------------------------------------+ | Field | Value | +----------------+--------------------------------------+ | action | CREATE | | created_at | 2016-04-19T17:44:04.000000 | | description | None | | email | admin@example.com | | id | 388814ef-3c5d-415e-a866-5b1d13d78dae | | masters | | | name | example.com. | | pool_id | 794ccc2c-d751-44fe-b57f-8894c9f5c842 | | project_id | 123456 | | serial | 1461087844 | | status | PENDING | | transferred_at | None | | ttl | 3600 | | type | PRIMARY | | updated_at | None | | version | 1 | +----------------+--------------------------------------+ See the new zone in your list of zones with the following command: .. code-block:: shell-session $ openstack zone list Display a specific zone with either of these commands; most zone commands accept either the zone_id or name attribute: .. code-block:: shell-session $ openstack zone show example.com. $ openstack zone show 388814ef-3c5d-415e-a866-5b1d13d78dae Update the zone with this command: .. code-block:: shell-session $ openstack zone set --description "Description" example.com. Delete the zone with this command: .. code-block:: shell-session $ openstack zone delete example.com. Working with Recordsets ''''''''''''''''''''''' Using the zone above, create a recordset with the following command: .. code-block:: shell-session $ openstack recordset create example.com. --type A www --records 192.0.2.20 +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | action | CREATE | | created_at | 2016-04-19T17:51:12.000000 | | description | None | | id | 180d3574-3c29-4ea2-b6ff-df904bd3f126 | | name | www.example.com. | | records | 192.0.2.20 | | status | PENDING | | ttl | None | | type | A | | updated_at | None | | version | 1 | | zone_id | 388814ef-3c5d-415e-a866-5b1d13d78dae | +-------------+--------------------------------------+ Multiple records can be provided for a specific recordset type: .. code-block:: shell-session $ openstack recordset create example.com. --type A www --records 192.0.2.20 192.0.2.21 See the new recordset in the list of recordsets with the following command: .. code-block:: shell-session $ openstack recordset list example.com. Display a specific recordset: .. code-block:: shell-session $ openstack recordset show example.com. www.example.com. Update a specific recordset: .. code-block:: shell-session $ openstack recordset set example.com. www.example.com. --ttl 10000 --records 192.0.2.20 192.0.2.21 Delete a recordset: .. code-block:: shell-session $ openstack recordset delete example.com. www.example.com. Working with PTR Records '''''''''''''''''''''''' Reverse DNS for Neutron Floating IPs can be managed with the "ptr" subcommand. Create a PTR record: .. code-block:: shell-session $ openstack ptr record set RegionOne:5c02c519-4928-4a38-bd10-c748c200912f ftp.example.com. +-------------+------------------------------------------------+ | Field | Value | +-------------+------------------------------------------------+ | action | CREATE | | address | 172.24.4.11 | | description | None | | id | RegionOne:5c02c519-4928-4a38-bd10-c748c200912f | | ptrdname | ftp.example.com. | | status | PENDING | | ttl | 3600 | +-------------+------------------------------------------------+ List all PTR records: .. code-block:: shell-session $ openstack ptr record list Show a PTR record: .. code-block:: shell-session $ openstack ptr record show RegionOne:5c02c519-4928-4a38-bd10-c748c200912f Delete a PTR record: .. code-block:: shell-session $ openstack ptr record delete RegionOne:5c02c519-4928-4a38-bd10-c748c200912f Working with Zone Exports ''''''''''''''''''''''''' Zone exports enable you to save Designate zone information offline. Create a zone export: .. code-block:: shell-session $ openstack zone export create example.com. +------------+--------------------------------------+ | Field | Value | +------------+--------------------------------------+ | created_at | 2016-04-19T20:42:16.000000 | | id | 6d5acb9d-f3d6-4ed4-96e1-03bc0e405bb5 | | location | None | | message | None | | project_id | 123456 | | status | PENDING | | updated_at | None | | version | 1 | | zone_id | 388814ef-3c5d-415e-a866-5b1d13d78dae | +------------+--------------------------------------+ List zone exports: .. code-block:: shell-session $ openstack zone export list Show zone export: .. code-block:: shell-session $ openstack zone export show 6d5acb9d-f3d6-4ed4-96e1-03bc0e405bb5 Show the zone file for the Zone Export: .. code-block:: shell-session $ openstack zone export showfile 6d5acb9d-f3d6-4ed4-96e1-03bc0e405bb5 -f value $ORIGIN example.com. $TTL 3600 example.com. IN NS ns2.exampleprovider.com. example.com. IN NS ns1.exampleprovider.com. example.com. IN SOA ns.exampleprovider.com. admin@example.com 1458678636 7200 300 604800 300 Delete zone export: .. code-block:: shell-session $ openstack zone export delete 6d5acb9d-f3d6-4ed4-96e1-03bc0e405bb5 Working with Zone Imports ''''''''''''''''''''''''' Zone imports enable you to import a zone into Designate from a file on the filesystem. Create a zone import from a file: .. code-block:: shell-session $ openstack zone import create zonefile.txt +------------+--------------------------------------+ | Field | Value | +------------+--------------------------------------+ | created_at | 2016-04-19T20:59:38.000000 | | id | bab6e152-da9f-4dfc-8a59-3f9710fe4894 | | message | None | | project_id | 123456 | | status | PENDING | | updated_at | None | | version | 1 | | zone_id | None | +------------+--------------------------------------+ List zone imports: .. code-block:: shell-session $ openstack zone import list Show zone import: .. code-block:: shell-session $ openstack zone import show 839d8041-1960-4d74-8533-118d52218074 Delete zone import: .. code-block:: shell-session $ openstack zone import delete 839d8041-1960-4d74-8533-118d52218074 Working with Zone Blacklists '''''''''''''''''''''''''''' Blacklisting zone names enables you to block any zone pattern from creation. Create a zone blacklist .. code-block:: shell-session $ openstack zone blacklist create --pattern "^example\.com\.$" --description "This is a blacklisted domain." +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | created_at | 2016-05-10 00:26:07 | | description | This is a blacklisted domain. | | id | 308ecb82-4952-4476-88b4-9db18fc78e10 | | pattern | ^example.com.$ | | updated_at | None | +-------------+--------------------------------------+ List zone blacklist .. code-block:: shell-session $ openstack zone blacklist list Show zone blacklist .. code-block:: shell-session $ openstack zone blacklist show 308ecb82-4952-4476-88b4-9db18fc78e10 Update zone blacklist .. code-block:: shell-session $ openstack zone blacklist set --pattern "^([A-Za-z0-9_\-]+\.)*example\.com\.$" --description "Updated the description" 308ecb82-4952-4476-88b4-9db18fc78e10 Delete a zone blacklist .. code-block:: shell-session $ openstack zone blacklist delete 308ecb82-4952-4476-88b4-9db18fc78e10 Working with Zone Transfers Between Projects '''''''''''''''''''''''''''''''''''''''''''' Zone Transfers enable you to perform the transfer of zone ownership to another project. Create a Zone Transfer Request .. code-block:: shell-session $ openstack zone transfer request create --target-project-id 9cc52dd7649c4aa99fa9db2fb94dabb8 53cdcf82-9e32-4a00-a90d-32d6ec5db7e9 +-------------------+----------------------------------------------------------------------------------------+ | Field | Value | +-------------------+----------------------------------------------------------------------------------------+ | created_at | 2016-05-10 01:39:00 | | description | None | | id | 98ba1d22-c092-4603-891f-8a0ab04f7e57 | | key | J6JCET2C | | links | {u'self': | | | u'http://192.168.11.182:9001/v2/zones/tasks/transfer_requests/98ba1d22-c092-4603-891f- | | | 8a0ab04f7e57'} | | project_id | 10457ad1fe074f4a89bb1e4c0cd83d40 | | status | ACTIVE | | target_project_id | 9cc52dd7649c4aa99fa9db2fb94dabb8 | | updated_at | None | | zone_id | 53cdcf82-9e32-4a00-a90d-32d6ec5db7e9 | | zone_name | example.com. | +-------------------+----------------------------------------------------------------------------------------+ List Zone Transfer Requests .. code-block:: shell-session $ openstack zone transfer request list Show Zone Transfer Request Details .. code-block:: shell-session $ openstack zone transfer request show 98ba1d22-c092-4603-891f-8a0ab04f7e57 Update a Zone Transfer Request .. code-block:: shell-session $ openstack zone transfer request set 98ba1d22-c092-4603-891f-8a0ab04f7e57 --description "demo transfer" Delete a Zone Transfer Request .. code-block:: shell-session $ openstack zone transfer request delete 98ba1d22-c092-4603-891f-8a0ab04f7e57 Accept a Zone Transfer Request .. code-block:: shell-session $ openstack zone transfer accept request --transfer-id 98ba1d22-c092-4603-891f-8a0ab04f7e57 --key J6JCET2C +--------------------------+---------------------------------------------------------------------------------+ | Field | Value | +--------------------------+---------------------------------------------------------------------------------+ | created_at | 2016-05-10 05:02:52 | | id | a8750f50-d7e6-403a-89d2-e209d62ef60e | | key | J6JCET2C | | links | {u'self': | | | u'http://192.168.11.182:9001/v2/zones/tasks/transfer_accepts/a8750f50-d7e6 | | | -403a-89d2-e209d62ef60e', u'zone': | | | u'http://192.168.11.182:9001/v2/zones/53cdcf82-9e32-4a00-a90d-32d6ec5db7e9'} | | project_id | 10457ad1fe074f4a89bb1e4c0cd83d40 | | status | COMPLETE | | updated_at | 2016-05-10 05:02:52 | | zone_id | 53cdcf82-9e32-4a00-a90d-32d6ec5db7e9 | | zone_transfer_request_id | 98ba1d22-c092-4603-891f-8a0ab04f7e57 | +--------------------------+---------------------------------------------------------------------------------+ Show Zone Transfer Accept .. code-block:: shell-session $ openstack zone transfer accept show a8750f50-d7e6-403a-89d2-e209d62ef60e List Zone Transfer Accept .. code-block:: shell-session $ openstack zone transfer accept list Working with Top Level Domains '''''''''''''''''''''''''''''' The tld commands enable you to manage top level domains. Create a TLD .. code-block:: shell-session $ openstack tld create --name com --description "demo TLD" +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | created_at | 2016-05-10 05:21:40 | | description | demo TLD | | id | a7bba387-712b-4b42-9368-4508642c6113 | | name | com | | updated_at | None | +-------------+--------------------------------------+ List TLDs .. code-block:: shell-session $ openstack tld list Show TLD Details .. code-block:: shell-session $ openstack tld show a7bba387-712b-4b42-9368-4508642c6113 Update a TLD .. code-block:: shell-session $ openstack tld set a7bba387-712b-4b42-9368-4508642c6113 --name org --description "TLD description" Delete a TLD .. code-block:: shell-session $ openstack tld delete a7bba387-712b-4b42-9368-4508642c6113 .. _OpenStack Client configuration documentation: https://docs.openstack.org/python-openstackclient/latest/configuration/index.html python-designateclient-2.11.0/doc/examples/0000775000175000017500000000000013366600247020670 5ustar zuulzuul00000000000000python-designateclient-2.11.0/doc/examples/recordset_create.py0000666000175000017500000000241313366577761024577 0ustar zuulzuul00000000000000from __future__ import print_function import logging from designateclient.v2 import client from designateclient import exceptions from designateclient import shell from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session logging.basicConfig(level='DEBUG') """ Example script to create or get a domain and add some records to it. """ auth = generic.Password( auth_url=shell.env('OS_AUTH_URL'), username=shell.env('OS_USERNAME'), password=shell.env('OS_PASSWORD'), project_name=shell.env('OS_PROJECT_NAME'), project_domain_id='default', user_domain_id='default') session = keystone_session.Session(auth=auth) client = client.Client(session=session) try: zone = client.zones.create('i.io.', email='i@i.io') except exceptions.RemoteError: zone = dict([(z['name'], z) for z in client.zones.list()])['i.io.'] print("Recordset list...") for rs in client.recordsets.list(zone['id']): print(rs) # Here's an example of just passing "www" as the record name vs "www.i.io." records = ["10.0.0.1"] rs = client.recordsets.create(zone['id'], 'www', 'A', records) # Here we're replacing the records with new ones records = ["10.0.0.1", "10.0.0.5"] client.recordsets.update(zone['id'], rs['id'], {'records': records}) python-designateclient-2.11.0/doc/examples/recordset_crud.py0000666000175000017500000000356313366577761024300 0ustar zuulzuul00000000000000import logging from designateclient.v2 import client from designateclient import exceptions from designateclient import shell from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session logging.basicConfig(level='DEBUG') auth = generic.Password( auth_url=shell.env('OS_AUTH_URL'), username=shell.env('OS_USERNAME'), password=shell.env('OS_PASSWORD'), project_name=shell.env('OS_PROJECT_NAME'), project_domain_id='default', user_domain_id='default') session = keystone_session.Session(auth=auth) client = client.Client(session=session) try: zone = dict([(z['name'], z) for z in client.zones.list()])['i.io.'] client.zones.delete(zone['id']) except exceptions.NotFound: pass zone = client.zones.create(name='i.io.', email='i@i.io') # Clean all recordsets first in this zone (for sanity sake) for rrset in client.recordsets.list(zone['id']): if rrset['type'] in ('NS', 'SOA'): continue client.recordsets.delete(zone['id'], rrset['id']) # Make some A records www = client.recordsets.create( zone['id'], 'www.%s' % zone['name'], 'A', ['10.0.0.1']) values = { 'records': ['10.0.1.1', '10.0.0.2'] } client.recordsets.update(zone['id'], www['id'], values) cname = client.recordsets.create( zone['id'], 'my-site.%s' % zone['name'], 'CNAME', [www['name']]) # Now let's do some Mailserver examples # First create the A record mail1 = client.recordsets.create( zone['id'], 'mail1.' + zone['name'], 'A', ["10.0.0.11"]) mail2 = client.recordsets.create( zone['id'], 'mail2.' + zone['name'], 'A', ["10.0.0.12"]) # Create the MX records - it will be 1 recordset with multiple records pointing # to the A records we created above mx_rrset = client.recordsets.create( zone['id'], zone['name'], 'MX', ['0 ' + mail1['name'], '5 ' + mail2['name']]) print(zone['id']) python-designateclient-2.11.0/doc/examples/zone_list_paging.py0000666000175000017500000000161613366577761024621 0ustar zuulzuul00000000000000from __future__ import print_function import logging from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session from designateclient import shell from designateclient.v2 import client logging.basicConfig(level='DEBUG') auth = generic.Password( auth_url=shell.env('OS_AUTH_URL'), username=shell.env('OS_USERNAME'), password=shell.env('OS_PASSWORD'), project_name=shell.env('OS_PROJECT_NAME'), project_domain_id='default', user_domain_id='default') session = keystone_session.Session(auth=auth, timeout=10) client = client.Client(session=session) pages = [] fetch = 1 while fetch: kw = {'limit': 3} if pages: # marker is the latest page with the last item. kw['marker'] = pages[-1][-1]['id'] page = client.zones.list(**kw) if not page: break pages.append(page) for page in pages: print(page) python-designateclient-2.11.0/doc/examples/zone_create_secondary.py0000666000175000017500000000203713366577761025631 0ustar zuulzuul00000000000000import logging import uuid from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session from designateclient import exceptions from designateclient import shell from designateclient.v2 import client logging.basicConfig(level='DEBUG') auth = generic.Password( auth_url=shell.env('OS_AUTH_URL'), username=shell.env('OS_USERNAME'), password=shell.env('OS_PASSWORD'), project_name=shell.env('OS_PROJECT_NAME'), project_domain_id='default', user_domain_id='default') session = keystone_session.Session(auth=auth) client = client.Client(session=session) # Primary Zone primary = client.zones.create( 'primary-%s.io.' % str(uuid.uuid4()), 'PRIMARY', 'root@x.com') # Secondary Zone slave = client.zones.create( 'secondary-%s.io.' % str(uuid.uuid4()), 'SECONDARY', masters=["127.0.1.1"]) # Try updating Masters for the Secondary new_slave = client.zones.update( slave['id'], {"masters": ["10.0.0.1", "10.0.0.10"]} ) # List all Zones zones = client.zones.list() python-designateclient-2.11.0/doc/examples/zone_create_primary.py0000666000175000017500000000152313366577761025324 0ustar zuulzuul00000000000000from __future__ import print_function import logging from designateclient import exceptions from designateclient import shell from designateclient.v2 import client from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session logging.basicConfig(level='DEBUG') auth = generic.Password( auth_url=shell.env('OS_AUTH_URL'), username=shell.env('OS_USERNAME'), password=shell.env('OS_PASSWORD'), project_name=shell.env('OS_PROJECT_NAME'), project_domain_id='default', user_domain_id='default') session = keystone_session.Session(auth=auth) client = client.Client(session=session) try: zone = client.zones.create('i.io.', email='i@i.io') except exceptions.RemoteError: zone = dict([(z['name'], z) for z in client.zones.list()])['i.io.'] print(client.recordsets.list(zone['id'])) python-designateclient-2.11.0/doc/examples/zone_list_nameservers.py0000666000175000017500000000135713366577761025710 0ustar zuulzuul00000000000000import logging import uuid from designateclient.v2 import client from designateclient import shell from designateclient import utils from keystoneauth1.identity import generic from keystoneauth1 import session as keystone_session logging.basicConfig(level='DEBUG') auth = generic.Password( auth_url=shell.env('OS_AUTH_URL'), username=shell.env('OS_USERNAME'), password=shell.env('OS_PASSWORD'), project_name=shell.env('OS_PROJECT_NAME'), project_domain_id='default', user_domain_id='default') session = keystone_session.Session(auth=auth) client = client.Client(session=session) zone = client.zones.create( 'primary-%s.io.' % str(uuid.uuid4()), 'PRIMARY', 'root@x.com') client.nameservers.list(zone['id']) python-designateclient-2.11.0/doc/requirements.txt0000666000175000017500000000043613366577761022361 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD openstackdocstheme>=1.18.1 # Apache-2.0 python-designateclient-2.11.0/AUTHORS0000664000175000017500000000632513366600247017363 0ustar zuulzuul00000000000000Alex Monk Alok Jani Andreas Jaeger Andreas Jaeger Andreas Jaeger Andrew F. Ly Andrew Spiers Atsushi SAKAI Ben Nemec Betsy Luzader Brian DeHamer Cao Xuan Hoang Cedric Brandily Chaozhe.Chen Chen Christian Berendt Clenimar Filemon Davide Guerri Deepak Dirk Mueller Doug Hellmann Dougal Matthews Endre Karlson Endre Karlson Endre Karlson Eric Wehrmeister Federico Ceratto Flavio Percoco Graham Hayes Graham Hayes Graham Hayes Graham Hayes Hangdong Zhang James Li Janonymous Jens Harbott Jeremy Stanley Joe Gordon Jordan Cazamias KATO Tomoyuki Kiall Mac Innes Kiall Mac Innes Kiall Mac Innes Lakshmi N Sampath Marcus Furlong Monty Taylor Nguyen Hai Ondřej Nový OpenStack Release Bot Patrick Galbraith Paul Glass Pavel Kirpichyov Pradeep Kumar Singh Rahman Syed Reddy A, Penchal (pr8721) Rudolf Vriend Rui Chen Sascha Peilicke Sascha Peilicke Satyanarayana Patibandla Shane Wang Shuquan Huang Simon McCartney Stephen Finucane Swapnil Kulkarni (coolsvap) Tang Chen TerryHowe Tim Simmons Tony Breeds Tony Xu Venkata Mahesh Jonnalagadda Vieri <15050873171@163.com> Vu Cong Tuan abhishekkekane algerwang ashish-kumar-gupta ghanshyam howardlee lingyongxu melissaml miaoyuliang ricolin ricolin rjrjr sonu.kumar venkatamahesh python-designateclient-2.11.0/LICENSE0000666000175000017500000002363713366577761017345 0ustar zuulzuul00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. python-designateclient-2.11.0/bin/0000775000175000017500000000000013366600247017055 5ustar zuulzuul00000000000000python-designateclient-2.11.0/bin/designate0000777000175000017500000000140013366577761020761 0ustar zuulzuul00000000000000#!/usr/bin/env python # Copyright 2012 Managed I.T. # # Author: Kiall Mac Innes # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import sys from designateclient.shell import DesignateShell shell = DesignateShell() sys.exit(shell.run(sys.argv[1:])) python-designateclient-2.11.0/setup.py0000666000175000017500000000200613366577761020035 0ustar zuulzuul00000000000000# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT import setuptools # In python < 2.7.4, a lazy loading of package `pbr` will break # setuptools if some other modules registered functions in `atexit`. # solution from: http://bugs.python.org/issue15881#msg170215 try: import multiprocessing # noqa except ImportError: pass setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) python-designateclient-2.11.0/PKG-INFO0000664000175000017500000000523613366600247017410 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: python-designateclient Version: 2.11.0 Summary: OpenStack DNS-as-a-Service - Client Home-page: https://docs.openstack.org/python-designateclient/latest Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: Apache License, Version 2.0 Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/python-designateclient.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on Python bindings to the Designate API ===================================== .. image:: https://img.shields.io/pypi/v/python-designateclient.svg :target: https://pypi.org/project/python-designateclient/ :alt: Latest Version This is a client library for Designate built on the Designate API. It provides a Python API (the ``designateclient`` module) and a command-line tool (``designate``). Development takes place via the usual OpenStack processes as outlined in the `developer guide `_. The master repository is in `Git `_. See release notes and more at ``_. * License: Apache License, Version 2.0 * `PyPi`_ - package installation * `Online Documentation`_ * `Bugs`_ - issue tracking * `Source`_ * `How to Contribute`_ .. _PyPi: https://pypi.org/project/python-designateclient .. _Online Documentation: https://docs.openstack.org/python-designateclient/latest/ .. _Bugs: https://bugs.launchpad.net/python-designateclient .. _Source: https://git.openstack.org/cgit/openstack/python-designateclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Internet :: Name Service (DNS) python-designateclient-2.11.0/requirements.txt0000666000175000017500000000100213366577761021602 0ustar zuulzuul00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. cliff!=2.9.0,>=2.8.0 # Apache-2.0 jsonschema<3.0.0,>=2.6.0 # MIT osc-lib>=1.8.0 # Apache-2.0 oslo.utils>=3.33.0 # Apache-2.0 pbr!=2.1.0,>=2.0.0 # Apache-2.0 keystoneauth1>=3.4.0 # Apache-2.0 requests>=2.14.2 # Apache-2.0 six>=1.10.0 # MIT stevedore>=1.20.0 # Apache-2.0 debtcollector>=1.2.0 # Apache-2.0