././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/0000775000175100017510000000000015033037476015212 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/.coveragerc0000664000175100017510000000011615033037474017327 0ustar00mylesmyles[run] branch = True source = octavia_dashboard [report] ignore_errors = True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/.eslintrc0000664000175100017510000000263415033037474017041 0ustar00mylesmyles# Set up globals globals: angular: false extends: openstack # Most environment options are not explicitly enabled or disabled, only # included here for completeness' sake. They are commented out, because the # global updates.py script would otherwise override them during a global # requirements synchronization. # # Individual projects should choose which platforms they deploy to. env: # browser global variables. browser: true # Adds all of the Jasmine testing global variables for version 1.3 and 2.0. jasmine: true # Enable eslint-plugin-angular plugins: - angular # Below we adjust rules specific to horizon's usage of openstack's linting # rules, and its own plugin inclusions. rules: ############################################################################# # Disabled Rules from eslint-config-openstack ############################################################################# valid-jsdoc: 1 brace-style: 1 no-extra-parens: 1 consistent-return: 1 callback-return: 1 guard-for-in: 1 block-scoped-var: 1 semi-spacing: 1 no-redeclare: 1 no-new: 1 ############################################################################# # Angular Plugin Customization ############################################################################# angular/controller-as-vm: - 1 - "ctrl" # Remove after migrating to angular 1.4 or later. angular/no-cookiestore: - 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/.mailmap0000664000175100017510000000013115033037474016624 0ustar00mylesmyles# Format is: # # ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/.stestr.conf0000664000175100017510000000011315033037474017454 0ustar00mylesmyles[DEFAULT] test_path=${OS_TEST_PATH:-./octavia_dashboard/tests/} top_dir=./ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924541.0 octavia_dashboard-15.1.0.dev2/AUTHORS0000664000175100017510000000514215033037475016263 0ustar00mylesmylesAjay Kumar Akihiro Motoki Akihiro Motoki Andreas Jaeger Ann Taraday Carlos Goncalves Charles Short Corey Bryant Diana Whitten Dirk Mueller Doug Fish Doug Hellmann Doug Wiegley Elena Ezhova Emmanuel MISSIAEN Erik Olof Gunnar Andersson Flavio Percoco Frank Kloeker German Eichberger Ghanshyam Mann Gregory Thiemonge Hervé Beraud Jacky Hu James E. Blair Jesper Schmitz Mouridsen Justin Pomeroy Kyle Mestery Lucas Palm Luke Tollefson MaoyangLiu Mark Vanderwiel Matt Borland Michael Johnson MinSun Monty Taylor Nguyen Hai Nir Magnezi OpenStack Release Bot Pierre-Yves Jourel Praveen Yalagandula Qian Min Chen Rajiv Kumar Sam Morrison Sean McGinnis ShangXiao Steven Glasford Swapnil Kulkarni (coolsvap) Takashi Kajinami Takashi Kajinami Tom Weininger Tong Liu Vadym Markov Vieri <15050873171@163.com> Vivek Jain avnish chenxiangui coco-Gao <419546439@qq.com> howardlee huang.zhiping jacky06 lidong lilintan lioplhp manchandavishal mareklycka pengyuesheng qiaomin shangxiaobj sunxifa xuleibj ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/CONTRIBUTING.rst0000664000175100017510000000125015033037474017647 0ustar00mylesmylesIf you would like to contribute to the development of OpenStack, you must follow the steps in this page: https://docs.openstack.org/infra/manual/developers.html If you already have a good understanding of how the system works and your OpenStack accounts are set up, you can skip to the development workflow section of this documentation to learn how changes to OpenStack should be submitted for review via the Gerrit tool: https://docs.openstack.org/infra/manual/developers.html#development-workflow Pull requests submitted through GitHub will be ignored. Bugs should be filed on Storyboard, not GitHub or Launchpad: https://storyboard.openstack.org/#!/project/909 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924541.0 octavia_dashboard-15.1.0.dev2/ChangeLog0000664000175100017510000004111415033037475016764 0ustar00mylesmylesCHANGES ======= * Update master for stable/2025.1 15.0.0 ------ * Update python classifier as per the 2025.1 cycle testing runtime * reno: Update master for unmaintained/2023.1 * Drop unnecessary 'x' bit from doc config file * Update master for stable/2024.2 14.0.0 ------ * Fixed incorrect region endpoint in multi-region * reno: Update master for unmaintained/zed * Bump hacking * Remove old excludes * Imported Translations from Zanata * Update master for stable/2024.1 * reno: Update master for unmaintained/xena 13.0.0 ------ * reno: Update master for unmaintained/wallaby * reno: Update master for unmaintained/victoria * reno: Update master for unmaintained/yoga * Imported Translations from Zanata * Update python classifier in setup.cfg * Fix authentication issue with openstacksdk * Fix python shebang * Fix certificate list in listener edit box * Update master for stable/2023.2 12.0.0 ------ * Imported Translations from Zanata * Fix error related to barbicanclient * Fix popover attributes in member add dialog * Fix missing comma in example logger setting * Update master for stable/2023.1 * Imported Translations from Zanata 11.0.0 ------ * Fix new issue with tox4 * Fix tox.ini with tox4 * Remove hard-coded Python path in karma.conf.js * Imported Translations from Zanata * Add \*.orig to .gitignore * Fix ESLint warnings * Imported Translations from Zanata * Switch to 2023.1 Python3 unit tests and generic template name * Update master for stable/zed 10.0.0 ------ * Imported Translations from Zanata * Imported Translations from Zanata * Drop lower-constraints.txt and its testing * Remove unused oslo.log * Bump tox minversion to 3.18.0 * Replace deprecated ugettext\_lazy * Use Horizon project template for nodejs jobs * Migrate to AngularJS v1.8.2 * Move to Python 3.8 * Address RemovedInDjango40Warning * Add Python3 zed unit tests * Update master for stable/yoga 9.0.0 ----- * Display Draining state correctly * setup.cfg: Replace dashes by underscores * Updating python testing classifier as per Yoga testing runtime * Fix invalid value range for member weight * Fix network selector filter at LB creation * Add Python3 yoga unit tests * Update master for stable/xena 8.0.0 ----- * Change the Octavia Barbican namespace * Drop horizon-nodejs10-jobs template * Imported Translations from Zanata * Add example logging setting * Add horizon-nodejs14-job template * Fix updating a non-HTTP(S) Health Monitor * Fix deleting multiple resources * Add Python3 xena unit tests * Update master for stable/wallaby 7.0.0 ----- * Imported Translations from Zanata * Disable Load Balancers panel when Octavia service is not deployed * Allows creation of resources without forcing the creation of children * Add TLS enabled support for pools * Add ciphers options for listeners and pools * Imported Translations from Zanata * Remove unicode to adapt to python3 * Fix lower-constraints for new pip release * Add textarea field for allowed\_cidrs in the listener api * Imported Translations from Zanata * Add Python3 wallaby unit tests * Update master for stable/victoria * Add support for SCTP 6.0.0.0rc1 ---------- * [goal] Migrate testing to ubuntu focal * Add proxy protocol v2 support to dashboard * Fix up display of selected Availability zone in workflow * Imported Translations from Zanata * Bump the minimum openstacksdk version * drop mock from lower-constraints * Cleanup py27 support * Switch to newer openstackdocstheme and reno versions * Switch to hacking 3.0 * Imported Translations from Zanata * Add py38 package metadata * Imported Translations from Zanata * Imported Translations from Zanata * Add Python3 victoria unit tests * Update master for stable/ussuri 5.0.0.0rc1 ---------- * Availability zone support * Imported Translations from Zanata * Add missing fields for HTTPS health monitors * Fix pyScss version in lower-constraints.txt * Remove six usage * Drop Django 1.11 support * OpenStack is dropping the py2.7 support in ussuri cycle * translation: drop babel extractor definitions * Fix Django version in lower-constraints * Imported Translations from Zanata * Fix fip address display for loadbalancer * Imported Translations from Zanata * Switch to official Ussuri jobs * Use Horizon project template for django jobs * Imported Translations from Zanata * Imported Translations from Zanata * Update master for stable/train * Imported Translations from Zanata 4.0.0.0rc1 ---------- * Fix dashboard certificates skipping pkcs12 bundles * Enable fail-fast on the gate queue * Generate PDF documentation * Imported Translations from Zanata * Use lower-constraints template * Imported Translations from Zanata * Imported Translations from Zanata * Update api-ref location * Imported Translations from Zanata * Imported Translations from Zanata * Added UDP support for listener and health-monitor * Bump the openstackdocstheme extension to 1.20 * Sync Sphinx requirement * Imported Translations from Zanata * Imported Translations from Zanata * Add Python 3 Train unit tests * Update tox.ini for new upper constraints strategy * Remove reference to Neutron LBaaS dashboard * Fix devstack plugin python3 support * Fix 403 issue when creating load balancers * Imported Translations from Zanata * Changes for url transition to OpenDev * OpenDev Migration Patch * witch python3 versions of test jobs to match Train PTI * Drop nodejs4 jobs * Displays the subnet id when the subnet name is empty * Update master for stable/stein 3.0.0 ----- * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Add nodejs10 jobs on bionic * Switch to horizon-nodejs4-jobs template * Add load balancer flavor support * Imported Translations from Zanata * Fix auth url for Barbican client * Allow cascade deletion of load balancer * add python 3.7 unit test job * Imported Translations from Zanata * Imported Translations from Zanata * Honor OPENSTACK\_ENDPOINT\_TYPE in Horizon's local\_settings.py * Imported Translations from Zanata * Imported Translations from Zanata * Update hacking version * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Implements a filtered select * fix typo mistakes * Imported Translations from Zanata * Modify http to https * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Change openstack-dev to openstack-discuss * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Modify the wrong url * Imported Translations from Zanata * Imported Translations from Zanata * Update min tox version to 2.0 * Imported Translations from Zanata * Imported Translations from Zanata * Support the X-Forwarded-Proto insertion header * Show the 'Insert Headers' when listener protocol is 'HTTP' or 'TERMINATED\_HTTPS' * Increment versioning with pbr instruction * Imported Translations from Zanata * Add Python 3.6 unit test jobs * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * switch documentation job to new PTI * import zuul job settings from project-config * Imported Translations from Zanata * Remove obsolete gate hooks * Imported Translations from Zanata * Drop nose dependencies * Cannot update ssl certificate when update listener * Update reno for stable/rocky * Add Apple OS X ".DS\_Store" to ".gitignore" file 2.0.0.0rc1 ---------- * Set a minimum coverage threshold for javascript * Update octavia-dashboard tox for stestr * fix tox python3 overrides 2.0.0.0b2 --------- * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Allow detail pages to auto refresh upon action * Imported Translations from Zanata * Allow members to be set as "backup" * Allow member name to be set and updated * Imported Translations from Zanata * Replace noop tests with registration test * Fix sphinx-docs job for sphinx >1.7 * Imported Translations from Zanata * Imported Translations from Zanata * Imported Translations from Zanata * Add the missing type for Health Monitor * Make the display of none consistent in detail page * Add timeout options for listener * Replace unicode punctation with ascii 2.0.0.0b1 --------- * Being able to change insert headers of listener * Align model with v2 api * Use pool name as hint for selecting pool id * Add rbac support for octavia service apis * Add release notes link to README * add lower-constraints job * Add l7 support * Being able to edit default pool of listener * List children pools on LB details page * Update tox.ini * Add package-lock.json * Imported Translations from Zanata * Updated from global requirements * Updated from global requirements * Remove tox\_install * Imported Translations from Zanata * Imported Translations from Zanata * Adds some notes on enabling both dashboards * Imported Translations from Zanata * Updated from global requirements * Imported Translations from Zanata * Modify the '.gitignore' file * Update reno for stable/queens * Add the missing protocol for listener * Remove the unused codes 1.0.0.0rc1 ---------- * Imported Translations from Zanata * Imported Translations from Zanata * [trivial] fix typo in octavia\_dashboard lbaasv2 * Update docs config for storyboard bugs * Update the release notes for Queens * Show last updated timestamp for docs * Imported Translations from Zanata * Change "Method" to "Algorithm" in pool step * Setup octavia-dashboard for Queens release 1.0.0.0b3 --------- * i18n: Do not include html directives in translation strings * Updated from global requirements * Imported Translations from Zanata * Show certificates step only for secure listener * Able to change admin state for all resources * Handle singular and plural when deleting resources * Make breadcrumb same as other pages * Handle a resource delete race condition * Remove members with a pool id * Updated from global requirements * Update the installation and contributors documents * Remove oslosphinx from docs * Updated from global requirements * Updating for new sphinx docs jobs * Updated from global requirements * Catch up with horizon framework * Test requirements cleanup * Imported Translations from Zanata * Update gitignore * Make whitelist externals os agnostic * Imported Translations from Zanata * Use standard nodejs4 tests * Imported Translations from Zanata 1.0.0.0b2 --------- * Update openstacksdk construction to be forward compatible * Imported Translations from Zanata * Imported Translations from Zanata * Add delete to member row actions * Simplify the text of pool edit button * Able to change monitor address and port of member * Add release notes support to octavia-dashboard * Updated from global requirements * Able to edit connection limit of listener * Imported Translations from Zanata * Able to manipulate retries down of health monitor * Updated from global requirements * Zuul: add file extension to playbook path 1.0.0.0b1 --------- * Set package.json version to 1.0.0.0b1 Queens MS1 * Add created-at and updated-at to all detail pages * Move Octavia dashboard zuulv3 config in repo * Update tox\_install.sh for zuulv3 * Imported Translations from Zanata * Update health monitor max retries correctly * Allow updating expected codes on health monitor * Being able to change session persistence of pool * Pull action button right without floating around * Updated from global requirements * Add subnet\_id to member details page * Imported Translations from Zanata * Fix project requirements * Updated from global requirements * Use storyboard for bugs tracking * Updated from global requirements * Able to change lb algorithm on pool updating * Convert octavia-dashboard to use Octavia v2 API * Update links in README * Replace http with https for doc links in octavia-dashboard * Remove neutron-lbaas checks and rename "slug" * Remove old unused code * Updated from global requirements * Updated from global requirements * Get rid of removed Django code * Add loading and error status to detail pages * Update URL home-page in documents according to document migration * Fix URL patterns * Show the member status properties * Move FIP api from network to neutron * Make it work with devstack * Updated from global requirements * Optimize the link address * Updating for octavia-dashboard * Exclude node\_modules from pep8 checking * Fix npm test * Updated from global requirements * Replace SortedDict with OrderedDict and fixing Python 3.5 test * Updated from global requirements * Imported Translations from Zanata * Fix bugs URL for project ownership change * Imported Translations from Zanata * Added link to modindex * Updated from global requirements * Imported Translations from Zanata * Allow hacking 0.12.x * Imported Translations from Zanata * Imported Translations from Zanata * Update for ui bootstrap changes * Imported Translations from Zanata * Add Constraints support * Imported Translations from Zanata * Imported Translations from Zanata * Show team and repo badges on README * Using horizon's templateview instead of generic one from django * Imported Translations from Zanata * Updated from global requirements * Using oslo\_log instead of logging * Imported Translations from Zanata * Updated from global requirements * Drop MANIFEST.in - it's not needed by pbr * modify the home-page info with the developer documentation * Translation preparation for neutron-lbaas-dashboard * Don't include openstack/common in flake8 exclude list * Remove unused logging * Subnet dropdown list has empty fields * Remove discover from test-requirements * Fix list\_loadbalancers function * LBaaS dashboard resepects OPENSTACK\_SSL settings * Updated from global requirements * Fix devstack plugin clean-up * Updated from global requirements * Make Barbican client respect OPENSTACK\_ENDPOINT\_TYPE * Update load balancer wizard help * Updated from global requirements * Updated from global requirements * Updated from global requirements * fix unit tests * Improve the technique for generating default resource names * Indicate table loading, error, and empty states * Move to post versioning * Add release note for LBaaS v2 dashboard work in Mitaka * Do not allow deleting a listener that has a default pool * Hide load balancers v2 panel if not enabled * Add the Angular LBaaS V2 'Update Member List' Table Action * Reload route after performing actions * Add trailing slash to all URLs calling the REST API * Fix gate scripts to use script dir for sourcing commons * Add action for updating pool member weight * Add edit health monitor action * Add create health monitor action * Add health monitor delete action * Add the Angular LBaaS V2 'Edit Pool' Workflow * Add the Angular LBaaS V2 'Create Pool' workflow * Add pool delete action * Handle missing key-manager service in workflow * Add listener delete actions * Add the Angular LBaaS V2 'Create Listener' workflow * Update styles to match latest horizon * Add associate and disassociate floating IP actions * Add delete load balancer actions * Make workflow enforce all required fields * Clean up create load balancer workflow * Add support for TERMINATED\_HTTPS protocol * Add the angular LBaaS V2 Edit Action for Listeners * Remove page header from pages on tabs * Adding integration test support * Update install instruction for LBaaS v2 dashboard * Use the horizon limit filter for connection limit * Add general load balancer service * Use static file auto-discovery * Update URL routing * Updated from global requirements * Support external members when creating load balancer * Add the angular LBaaS V2 health monitor detail page * Add the angular LBaaS V2 members table and detail pages * Add the angular LBaaS V2 pools detail page * Fix typo in enable file * Add angular LBaaS V2 Listeners table and detail pages * Add support for editing a load balancer * Make create load balancer workflow generic * Add monitor tab to create load balancer workflow * Update npm dependencies * Add members tab to create load balancer workflow * Add listener and pool to create load balancer workflow * Include javascript lint and unit test in tox * Add initial workflow for creating load balancer * devstack plugin for neutron-lbaas-dashboard * Add routing and load balancer detail page * Add angular Load Balancers V2 panel * Initial commit for horizon lbaas v2 dashboard * Make sure django env var is set * Add requirement for testing * Open Mitaka development * Change ignore-errors to ignore\_errors * Initial cookiecutter commit * Added .gitreview ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/HACKING.rst0000664000175100017510000000023415033037474017005 0ustar00mylesmylesoctavia-dashboard Style Commandments ==================================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/LICENSE0000664000175100017510000002363715033037474016230 0ustar00mylesmyles 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. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/PKG-INFO0000644000175100017510000000715315033037476016313 0ustar00mylesmylesMetadata-Version: 2.2 Name: octavia-dashboard Version: 15.1.0.dev2 Summary: Horizon panels for Octavia Home-page: https://docs.openstack.org/octavia-dashboard/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org 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 :: Implementation :: CPython Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Requires-Python: >=3.9 License-File: LICENSE Requires-Dist: horizon>=17.1.0 Requires-Dist: Babel>=2.3.4 Requires-Dist: openstacksdk>=0.53.0 Requires-Dist: pbr>=2.0.0 Requires-Dist: python-keystoneclient>=3.22.0 Dynamic: author Dynamic: author-email Dynamic: classifier Dynamic: description Dynamic: home-page Dynamic: requires-dist Dynamic: requires-python Dynamic: summary ================= Octavia Dashboard ================= Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/octavia-dashboard.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on octavia-dashboard ================= Horizon panels for Octavia * Free software: Apache license * Documentation: https://docs.openstack.org/octavia-dashboard/latest/ * Source: https://opendev.org/openstack/octavia-dashboard * Release notes: https://docs.openstack.org/releasenotes/octavia-dashboard/ * Bugs: https://storyboard.openstack.org/#!/project/909 Features -------- * Please see octavia repository Howto ----- 1. Package the octavia_dashboard by running:: python setup.py sdist This will create a python egg in the dist folder, which can be used to install on the horizon machine or within horizon's python virtual environment. 2. Copy ``_1482_project_load_balancer_panel.py`` in ``octavia_dashboard/enabled`` directory to ``openstack_dashboard/local/enabled``:: $ cp -a \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/enabled/_1482_*.py \ ${HORIZON_DIR}/openstack_dashboard/local/enabled/ 3. (Optional) Generate the policy file and copy into horizon's policy files folder, and copy ``_1499_load_balancer_settings.py`` in ``octavia_dashboard/local_settings.d`` directory to ``openstack_dashboard/local/local_settings.d``:: $ oslopolicy-policy-generator \ --config-file \ ${OCTAVIA_DIR}/etc/policy/octavia-policy-generator.conf \ --output-file \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml $ cp -a \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml \ ${HORIZON_DIR}/openstack_dashboard/conf/ $ cp -a \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/local_settings.d/_1499_*.py \ ${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/ 4. Django has a compressor feature that performs many enhancements for the delivery of static files. If the compressor feature is enabled in your environment (``COMPRESS_OFFLINE = True``), run the following commands:: $ ./manage.py collectstatic $ ./manage.py compress 5. Finally restart your web server to enable octavia-dashboard in your Horizon:: $ sudo service apache2 restart ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/README.rst0000664000175100017510000000453615033037474016707 0ustar00mylesmyles================= Octavia Dashboard ================= Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/octavia-dashboard.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on octavia-dashboard ================= Horizon panels for Octavia * Free software: Apache license * Documentation: https://docs.openstack.org/octavia-dashboard/latest/ * Source: https://opendev.org/openstack/octavia-dashboard * Release notes: https://docs.openstack.org/releasenotes/octavia-dashboard/ * Bugs: https://storyboard.openstack.org/#!/project/909 Features -------- * Please see octavia repository Howto ----- 1. Package the octavia_dashboard by running:: python setup.py sdist This will create a python egg in the dist folder, which can be used to install on the horizon machine or within horizon's python virtual environment. 2. Copy ``_1482_project_load_balancer_panel.py`` in ``octavia_dashboard/enabled`` directory to ``openstack_dashboard/local/enabled``:: $ cp -a \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/enabled/_1482_*.py \ ${HORIZON_DIR}/openstack_dashboard/local/enabled/ 3. (Optional) Generate the policy file and copy into horizon's policy files folder, and copy ``_1499_load_balancer_settings.py`` in ``octavia_dashboard/local_settings.d`` directory to ``openstack_dashboard/local/local_settings.d``:: $ oslopolicy-policy-generator \ --config-file \ ${OCTAVIA_DIR}/etc/policy/octavia-policy-generator.conf \ --output-file \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml $ cp -a \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml \ ${HORIZON_DIR}/openstack_dashboard/conf/ $ cp -a \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/local_settings.d/_1499_*.py \ ${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/ 4. Django has a compressor feature that performs many enhancements for the delivery of static files. If the compressor feature is enabled in your environment (``COMPRESS_OFFLINE = True``), run the following commands:: $ ./manage.py collectstatic $ ./manage.py compress 5. Finally restart your web server to enable octavia-dashboard in your Horizon:: $ sudo service apache2 restart ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924542.0 octavia_dashboard-15.1.0.dev2/RELEASENOTES.rst0000664000175100017510000006432315033037476017645 0ustar00mylesmyles================= octavia-dashboard ================= .. _octavia-dashboard_1.0.2: 1.0.2 ===== .. _octavia-dashboard_1.0.2_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml @ b'8767e127723c95bab432a138907a692f2c1b6669' - Fixed an issue where TERMINATED_HTTPS listener type was greyed out. .. _octavia-dashboard_1.0.0: 1.0.0 ===== .. _octavia-dashboard_1.0.0_Prelude: Prelude ------- .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' The Octavia team is excited to release the 1.0.0 version of the Octavia dashboard. This dashboard uses the Octavia API endpoint via the openstacksdk. This release includes a number of improvements over the old neutron-lbaas-dashboard that worked against the neutron API endpoint. These improvements are listed below in the features section of this release note. .. _octavia-dashboard_1.0.0_New Features: New Features ------------ .. releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - A new dashboard wizard for Octavia. Allows you to create an Octavia load balancer and related resources such as a listener, pool, pool members, and health monitor. .. releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - A view of all the existing Octavia load balancers. .. releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Ability to view details of a Octavia load balancer and drill down to see details for the listener, pool, pool member, and health monitor resources. .. releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Ability to create, update, and delete the Octavia load balancer, listener, pool, pool member, and health monitor resources. .. releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Ability to associate and disassociate floating IP addresses for a load balancer. .. releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Ability to choose from SSL certificates stored by the key-manager service when creating a listener using the TERMINATED_HTTPS protocol. .. releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Ability to choose from existing instances from the compute service or specify external members when adding members to a pool. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - The object details pages now use a tabbed navigation for child objects. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Provisioning and operating status is now available on all object details pages. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Pools can now change the load balancing algorithm after creation. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Members now display the subnet_id on the details page. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Health monitors can now change the expected HTTP codes. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - The session persistence for a pool can now be changed. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Created at and Updated at times are now visible on the details pages. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Health monitors can now use alternate IP addresses and ports. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - Listener connection limits can now be updated. .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - All objects now allow setting the "Admin State". .. _octavia-dashboard_1.0.0_Known Issues: Known Issues ------------ .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - The octavia-dashboard requires openstacksdk >= 0.10.0 to resolve an issue with displaying the health monitor details page. It is expected this will be included in the OpenStack Queens release. .. _octavia-dashboard_1.0.0_Upgrade Notes: Upgrade Notes ------------- .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - This dashboard can be used alongside the neutron-lbaas-dashboard, but both dashboard panels will use the "Load Balancer" labels. .. _octavia-dashboard_1.0.0_Other Notes: Other Notes ----------- .. releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml @ b'199de4dc94012fd0deafdef3bf1e4207192be2f4' - The neutron-lbaas neutron extension is not required to use this dashboard. Load balancers created with neutron-lbaas that have not been migrated to Octavia may not be accessible via this dashboard. Only resources accessible via the Octavia API will be visible in this dashboard. .. _octavia-dashboard_2.0.1: 2.0.1 ===== .. _octavia-dashboard_2.0.1_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml @ b'7ab1553c42f89b8afcd8d07f2aeb728fc4548d49' - Fixed an issue where TERMINATED_HTTPS listener type was greyed out. .. _octavia-dashboard_2.0.0: 2.0.0 ===== .. _octavia-dashboard_2.0.0_New Features: New Features ------------ .. releasenotes/notes/add-RBAC-43ee180e712294ed.yaml @ b'd90c3bf03a2e7783f4088680c2f2c4328870b725' - Adds RBAC support to the dashboard panels. .. releasenotes/notes/add-insert-headers-a6fd80c837a89536.yaml @ b'05170ec174ebbcaa7a32db0a9541d5078fa354ea' - Adds the ability to set the insertion headers on listeners. .. releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml @ b'5b7326405aab97fe8c976d1dc16ff8c2a65fa788' - Adds L7 policy support to the dashboard. .. releasenotes/notes/add-member-backup-32e2ec2553c1ba24.yaml @ b'f1194d2dc1315fda371d5d27115aa8fd5de94ea4' - Adds the ability to set member as backup. .. releasenotes/notes/add-timeout-options-8988fc477fa46d31.yaml @ b'e98966c795e86da5cfa0f4c26276241b4e398133' - Adds the ability to set the timeout options on listeners. .. releasenotes/notes/auto-refresh-detail-pages-26166d5d9c26edee.yaml @ b'bb0cb8645125b4acd524ed69b0fafcfc32d94d75' - Adds the ability to auto refresh detail pages upon action. .. releasenotes/notes/edit-default-pool-on-listener-206d8dfeea135360.yaml @ b'e9b3988a9d49f76cef0e145c9feeef11f6273208' - You can now change the default pool on listeners. .. releasenotes/notes/list-pools-on-lb-details-page-eb0400bdb2b3650f.yaml @ b'9711760b337a8f887c19ad3ffb09c4eabe9ff90a' - Pools attached to a load balancer are now listed on the load balancer details page. .. releasenotes/notes/pool-selection-hint-7f282ba1fa014d8c.yaml @ b'2f6e2a386c4c499a299d7e6eaf0778904a5e2b17' - The pool name is now visible in pool selection drop downs in addition to the pool ID. .. _octavia-dashboard_2.0.0_Upgrade Notes: Upgrade Notes ------------- .. releasenotes/notes/add-RBAC-43ee180e712294ed.yaml @ b'd90c3bf03a2e7783f4088680c2f2c4328870b725' - To enable RBAC support in the Octavia dashboard you need to install the generated octavia_dashboard/conf/octavia_policy.yaml file into your horizon openstack_dashboard/conf/ directory and also copy octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py file into your horizon openstack_dashboard/local/local_settings.d/ directory. .. _octavia-dashboard_2.0.0_Security Issues: Security Issues --------------- .. releasenotes/notes/add-RBAC-43ee180e712294ed.yaml @ b'd90c3bf03a2e7783f4088680c2f2c4328870b725' - RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC in the dashboard or not, the API RBAC will still be in effect. Enabling RBAC in the dashboard will enforce the policies in the dashboard before the API call is made. .. _octavia-dashboard_3.0.1: 3.0.1 ===== .. _octavia-dashboard_3.0.1_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-flavor-no-flavor-profile-c3e82325f16d5ab8.yaml @ b'74a07c9c027ecfa95b2431f2a80556f4c0e9f544' - Fixes an issue in the Octavia dashboard where users receive a 403 error when attempting to create a load balancer. This was due to the dashboard attempting to access the flavor profile information which is an administrator only object by default. .. _octavia-dashboard_3.0.0: 3.0.0 ===== .. _octavia-dashboard_3.0.0_New Features: New Features ------------ .. releasenotes/notes/add-x-forwarded-proto-e30b52a3f853ed62.yaml @ b'90aa0f41f4e8462bed0b8ea83cfebe371f068424' - Adds the ability to set the X-Forwarded-Proto insertion header on listeners. .. releasenotes/notes/cascade-delete-e4c9d80a31076540.yaml @ b'72f8ff16eb20592cfa9bd3300b032ca6d664f72d' - Allow cascade deletion of load balancer. .. releasenotes/notes/filter-select-65160dcbe699a96d.yaml @ b'35f6f90d0cb28c444380d477f9558bd4bef11ff8' - Adds a new UI component which works as a standard select control alternative. Options in the component are presented in a table which may be filtered using the select input field. Filtering is done across all table fields. .. releasenotes/notes/flavor-support-0195a486faa16b7f.yaml @ b'38e835ceea39849a0789fc4f49cfd8aacf75527b' - Add load balancer flavor support. .. _octavia-dashboard_3.0.0_Known Issues: Known Issues ------------ .. releasenotes/notes/flavor-support-0195a486faa16b7f.yaml @ b'38e835ceea39849a0789fc4f49cfd8aacf75527b' - The octavia-dashboard requires openstacksdk > 0.24.0 for flavor support. .. _octavia-dashboard_3.0.0_Upgrade Notes: Upgrade Notes ------------- .. releasenotes/notes/filter-select-65160dcbe699a96d.yaml @ b'35f6f90d0cb28c444380d477f9558bd4bef11ff8' - The new component replaces the standard select for subnet selection in the Load Balancer creation modal wizard. .. _octavia-dashboard_3.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml @ b'9fc4b035cf34445c5a3079b4d183b9bce5a8c741' - Fixed an issue where TERMINATED_HTTPS listener type was greyed out. .. _octavia-dashboard_3.0.0_Other Notes: Other Notes ----------- .. releasenotes/notes/cascade-delete-e4c9d80a31076540.yaml @ b'72f8ff16eb20592cfa9bd3300b032ca6d664f72d' - This changed the default behavior of load balancer deletion from non-cascade deletion to cascade deletion. .. _octavia-dashboard_4.0.2-5: 4.0.2-5 ======= .. _octavia-dashboard_4.0.2-5_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml @ b'2358084a5329a4a24e3cc23ab16d6637e7c07769' - Fixes a namespace collision with the barbican-ui dashboard. .. releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml @ b'12ca23a55225b66767f343a63559c0e2a8753216' - Draining state was missing from the list of operating states. .. releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml @ b'2cce98b2080c156ca929aa1ac2a20449ef61924c' - Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. .. releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml @ b'7b08299d0f9079bed792e71d45932ec2fe8bfd2c' - Octavia supports setting the weight of members from 0 to 256, but in Horizon the value 0 was not accepted. This fix allows entering the value 0 as well, which is important for putting a member into DRAINING state. .. _octavia-dashboard_4.0.0: 4.0.0 ===== .. _octavia-dashboard_4.0.0_New Features: New Features ------------ .. releasenotes/notes/add-udp-support-acb1a22fb605d3a8.yaml @ b'0e190f92d74cbb2677a390a00b4826b6835b1e93' - Added UDP protocol support in listeners and pools, added UDP-CONNECT method for health-monitor resources. .. _octavia-dashboard_4.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-flavor-no-flavor-profile-c3e82325f16d5ab8.yaml @ b'a27ed69f1e97294a4672b3f815495baaedbf01ee' - Fixes an issue in the Octavia dashboard where users receive a 403 error when attempting to create a load balancer. This was due to the dashboard attempting to access the flavor profile information which is an administrator only object by default. .. _octavia-dashboard_5.0.2-4: 5.0.2-4 ======= .. _octavia-dashboard_5.0.2-4_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml @ b'843ac515795b70d2a055556602be69f24fb164c0' - Draining state was missing from the list of operating states. .. releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml @ b'639842181f143f0265ac6c7f470fdbbf3365edd6' - Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. .. releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml @ b'd11d0fe4e6368d4acda303578d8e7ebaaab89ceb' - Octavia supports setting the weight of members from 0 to 256, but in Horizon the value 0 was not accepted. This fix allows entering the value 0 as well, which is important for putting a member into DRAINING state. .. releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml @ b'58cbf93412b8eb67340f5e71e9da45cbee378a38' - Fix a bug that prevented the update of non-HTTP and non-HTTPS health monitors. .. _octavia-dashboard_5.0.2: 5.0.2 ===== .. _octavia-dashboard_5.0.2_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml @ b'fd73b213026617a2949cebcc834b84246dd540a3' - Fixes a namespace collision with the barbican-ui dashboard. .. _octavia-dashboard_5.0.0: 5.0.0 ===== .. _octavia-dashboard_5.0.0_New Features: New Features ------------ .. releasenotes/notes/add-az-support-efdd4e7c5dccef21.yaml @ b'761408e3b83712baa7ca281ab1685255d70b13c3' - Added support for availability zones. Can now create a LB in a specific AZ. .. _octavia-dashboard_5.0.0_Upgrade Notes: Upgrade Notes ------------- .. releasenotes/notes/drop-py-2-7-f3372b5c26171513.yaml @ b'2fd7d6ede223fcff626cea0f9ff2091f72986f75' - Python 2.7 support has been dropped. Last release of octavia-dashboard to support py2.7 is OpenStack Train. The minimum version of Python now supported by octavia-dashboard is Python 3.6. .. _octavia-dashboard_6.0.1-6: 6.0.1-6 ======= .. _octavia-dashboard_6.0.1-6_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml @ b'28ea78031dd6a1ebbeafd01556b6ef8b9c547c97' - Draining state was missing from the list of operating states. .. releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml @ b'4f7942ce32721009b8675b8994cd0ecff14afb9c' - Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. .. releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml @ b'96cdde26e7e25305839f09516fd67fa707e5be54' - Octavia supports setting the weight of members from 0 to 256, but in Horizon the value 0 was not accepted. This fix allows entering the value 0 as well, which is important for putting a member into DRAINING state. .. releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml @ b'bfac0145e6dd86a3b4a3534c5b98786a027a5462' - Fix a bug that prevented the update of non-HTTP and non-HTTPS health monitors. .. _octavia-dashboard_6.0.1: 6.0.1 ===== .. _octavia-dashboard_6.0.1_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml @ b'3aef1f7423052a161d9cc500e8fef789fc26bc28' - Fixes a namespace collision with the barbican-ui dashboard. .. _octavia-dashboard_6.0.0: 6.0.0 ===== .. _octavia-dashboard_6.0.0_New Features: New Features ------------ .. releasenotes/notes/Add-ProxyV2-b5537c092737fe41.yaml @ b'6a8f8807eb7f75960f156510546a20e07aedcce3' - Added Octavia dashboard support for proxy protocol version 2. .. _octavia-dashboard_7.0.1-4: 7.0.1-4 ======= .. _octavia-dashboard_7.0.1-4_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml @ b'2bca0ed072bf16833007acc45d3c1c359e894b03' - Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. .. releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml @ b'057404a134e3398db7f7d247b76434afc6be1fa6' - Fix a bug that prevented the update of non-HTTP and non-HTTPS health monitors. .. _octavia-dashboard_7.0.1: 7.0.1 ===== .. _octavia-dashboard_7.0.1_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml @ b'b4c76b96868dd22d5d1f306ac01129eb882e2d74' - Fixes a namespace collision with the barbican-ui dashboard. .. releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml @ b'76cf920eb476d0a8313e22a112c19429e77c7d14' - Draining state was missing from the list of operating states. .. releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml @ b'fc24b8495f9abcd59d6548e36993740c08346dd7' - Octavia supports setting the weight of members from 0 to 256, but in Horizon the value 0 was not accepted. This fix allows entering the value 0 as well, which is important for putting a member into DRAINING state. .. _octavia-dashboard_7.0.0: 7.0.0 ===== .. _octavia-dashboard_7.0.0_New Features: New Features ------------ .. releasenotes/notes/add-allowed-cidrs-ad205b1524da3d2c.yaml @ b'f4417cb97dab2cdc4cadab47f06660ce55c8609c' - Add the ability to set allowed_cidrs on the listeners .. releasenotes/notes/add-ciphers-options-for-listeners-and-pools-8440eaf5a551c44c.yaml @ b'daae6d1fcd432d0885880709dcbfd06140715644' - Added option to specify TLS ciphers for listeners and pools. The ciphers are represented in OpenSSL syntax. .. releasenotes/notes/add-sctp-support-a1ea956b7630f47d.yaml @ b'260ec7610ca6006bd2a57dbb771f6683a10c6004' - Add SCTP support in listener protocol and health-monitor type select boxes. .. releasenotes/notes/add-tls_enabled-support-for-pools-449e39f851535839.yaml @ b'400c1194e09e70c0b28e24fbdc27426626f3bd3a' - Add TLS Enabled switch in the pool control form, allowing to enable/disable TLS communications between a load balancer and its members. .. _octavia-dashboard_7.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/allows-creation-of-single-resources-9ec5fe87acc7c93c.yaml @ b'6ce037518a770486631c132d85caa9006c172195' - Allows the creation of single resources (i.e Load Balancer) without enforcing the creation of children resources (Listeners, Pools, Health monitors). A switch has been added in the children resource wizards to avoid resource creation. .. _octavia-dashboard_8.0.1-4: 8.0.1-4 ======= .. _octavia-dashboard_8.0.1-4_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml @ b'3eae62925e4aadfb70c7ff2d4a7d0970a6df1906' - Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. .. releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml @ b'd5ff7fed229643a937c01219447fee851a1f2afa' - Fix a bug that prevented the update of non-HTTP and non-HTTPS health monitors. .. _octavia-dashboard_8.0.1: 8.0.1 ===== .. _octavia-dashboard_8.0.1_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml @ b'775cf1399ef9a88f199cebbc06ccad5611f5dae6' - Draining state was missing from the list of operating states. .. releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml @ b'7298c1a46f8b1bf7e5dec874482704fc83caf1ae' - Octavia supports setting the weight of members from 0 to 256, but in Horizon the value 0 was not accepted. This fix allows entering the value 0 as well, which is important for putting a member into DRAINING state. .. _octavia-dashboard_8.0.0: 8.0.0 ===== .. _octavia-dashboard_8.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml @ b'7e390312eaf3cbbf89d46b05dd20b5296d61616d' - Fixes a namespace collision with the barbican-ui dashboard. .. _octavia-dashboard_9.0.1: 9.0.1 ===== .. _octavia-dashboard_9.0.1_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml @ b'b7785d206e50634b9d6f72b10433b0654470eef6' - Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. .. releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml @ b'74124028948ccef34f477856ccbe224f326926d9' - Fix a bug that prevented the update of non-HTTP and non-HTTPS health monitors. .. _octavia-dashboard_9.0.0: 9.0.0 ===== .. _octavia-dashboard_9.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml @ b'6fdab4a6c0803f96add2d1bdc52e2010790c1f66' - Draining state was missing from the list of operating states. .. releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml @ b'b1a86bb6ff3fa784b733641594eea86c2bb008d9' - Octavia supports setting the weight of members from 0 to 256, but in Horizon the value 0 was not accepted. This fix allows entering the value 0 as well, which is important for putting a member into DRAINING state. .. _octavia-dashboard_10.0.1: 10.0.1 ====== .. _octavia-dashboard_10.0.1_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml @ b'bd1a329b46d18baa42a9ba48d8031549a97a7bf2' - Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. .. _octavia-dashboard_10.0.0: 10.0.0 ====== .. _octavia-dashboard_10.0.0_Upgrade Notes: Upgrade Notes ------------- .. releasenotes/notes/move-to-python-3.8-86095fce6076fb37.yaml @ b'537865d2faa6f6d1cc5f566efbc73ed19870e410' - Update Python base version from 3.6 to 3.8. As per Openstack Python runtime versions policy Python 3.8 is the minimum Python version in the Zed release cycle. .. _octavia-dashboard_10.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml @ b'a8dc94fdbd4b46b16d77a2cd63931ee4078e48f9' - Fix a bug that prevented the update of non-HTTP and non-HTTPS health monitors. .. _octavia-dashboard_2023.1-eom: 2023.1-eom ========== .. _octavia-dashboard_2023.1-eom_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml @ b'6f990e09e7681bd63b784dad40e8def794fceb71' - Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. .. releasenotes/notes/remove-barbicanclient-6b48fcc36afafb62.yaml @ b'fa8fbcfcf83a0d3ea7b3431d8381d6bd13bfca1a' - Barbicanclient caused an error when getting secrets. By replacing the code by OpenstackSDK this issue was fixed and the barbicanclient dependency could be dropped from the Octavia Dashboard. .. _octavia-dashboard_2023.2-eol: 2023.2-eol ========== .. _octavia-dashboard_2023.2-eol_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-incorrect-region-endpoint-1afc5ebdc6fc4110.yaml @ b'd1cbc07614e62b837845714bb49ff28dab46908a' - Fixed a bug when using multi-region deployments, the octavia-dashboard may have used the wrong keystone catalog to get the load-balancer endpoint. .. _octavia-dashboard_12.0.0: 12.0.0 ====== .. _octavia-dashboard_12.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml @ b'9cc4bfac58b901b32c58d36ffab3585645f79be5' - Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. .. releasenotes/notes/remove-barbicanclient-6b48fcc36afafb62.yaml @ b'6fb6871ee0fe22b4e661edf8edc5a93129affa98' - Barbicanclient caused an error when getting secrets. By replacing the code by OpenstackSDK this issue was fixed and the barbicanclient dependency could be dropped from the Octavia Dashboard. .. _octavia-dashboard_13.0.0-3: 13.0.0-3 ======== .. _octavia-dashboard_13.0.0-3_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-incorrect-region-endpoint-1afc5ebdc6fc4110.yaml @ b'df12d4f080df1330c24abce7e5c3b14c4641b3ce' - Fixed a bug when using multi-region deployments, the octavia-dashboard may have used the wrong keystone catalog to get the load-balancer endpoint. .. _octavia-dashboard_13.0.0: 13.0.0 ====== .. _octavia-dashboard_13.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-auth-issue-5226777261765699.yaml @ b'92d72f1220efbe6f21181befbdb3de0d28670af2' - Fixed an authentication issue with the OpenStack services. The dashboard could not get the list of load balancers. .. _octavia-dashboard_14.0.0: 14.0.0 ====== .. _octavia-dashboard_14.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-incorrect-region-endpoint-1afc5ebdc6fc4110.yaml @ b'0f59b0d164ee0bfe106189a2704c6bfd5626df7b' - Fixed a bug when using multi-region deployments, the octavia-dashboard may have used the wrong keystone catalog to get the load-balancer endpoint. .. _octavia-dashboard_15.0.0: 15.0.0 ====== .. _octavia-dashboard_15.0.0_Bug Fixes: Bug Fixes --------- .. releasenotes/notes/fix-certificate-list-listener-edit-1d9775d23692c34b.yaml @ b'dd345707c1b7b877f623322c00ed7969edc15189' - Fix a bug that prevented to display the ``default_tls_container_ref`` when editing an HTTP_TERMINATED listener. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/babel-django.cfg0000664000175100017510000000011215033037474020170 0ustar00mylesmyles[python: **.py] [django: templates/**.html] [django: **/templates/**.csv] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/babel-djangojs.cfg0000664000175100017510000000006115033037474020530 0ustar00mylesmyles[javascript: **.js] [angular: **/static/**.html] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/bindep.txt0000664000175100017510000000060215033037474017210 0ustar00mylesmyles# This is a cross-platform list tracking distribution packages needed for install and tests; # see https://docs.openstack.org/infra/bindep/ for additional information. libfontconfig1 [nodejs platform:dpkg] # selenium tests ffmpeg [selenium] firefox [selenium] xvfb [selenium platform:dpkg] # already part of xorg-x11-server on openSUSE xorg-x11-server-Xvfb [selenium platform:redhat] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4641008 octavia_dashboard-15.1.0.dev2/devstack/0000775000175100017510000000000015033037476017016 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/devstack/README.rst0000664000175100017510000000134415033037474020505 0ustar00mylesmyles================================= Octavia dashboard devstack plugin ================================= This directory contains the octavia-dashboard devstack plugin. To enable the plugin, add the following to your local.conf: enable_plugin octavia-dashboard [GITREF] where is the URL of a octavia-dashboard repository [GITREF] is an optional git ref (branch/ref/tag). The default is master. For example: enable_plugin octavia-dashboard https://opendev.org/openstack/octavia-dashboard Once you enable the plugin in your local.conf, ensure ``horizon`` and ``o-api`` services are enabled. If both of them are enabled, octavia-dashboard will be enabled automatically ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/devstack/plugin.sh0000664000175100017510000000357315033037474020656 0ustar00mylesmylesfunction octavia_dashboard_install { setup_develop ${OCTAVIA_DASHBOARD_DIR} } function octavia_dashboard_configure { cp -a ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/enabled/_1482_project_load_balancer_panel.py ${HORIZON_DIR}/openstack_dashboard/local/enabled/ cp -a ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py ${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/ oslopolicy-policy-generator --config-file ${OCTAVIA_DIR}/etc/policy/octavia-policy-generator.conf --output-file ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml cp -a ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml ${HORIZON_DIR}/openstack_dashboard/conf/ if [[ -d ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/locale ]]; then (cd ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard; DJANGO_SETTINGS_MODULE=openstack_dashboard.settings $PYTHON ../manage.py compilemessages) fi } if is_service_enabled horizon && is_service_enabled o-api; then if [[ "$1" == "stack" && "$2" == "install" ]]; then # Perform installation of service source echo_summary "Installing octavia-dashboard" octavia_dashboard_install elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then echo_summary "Configuring octavia-dashboard" octavia_dashboard_configure elif [[ "$1" == "stack" && "$2" == "extra" ]]; then : fi if [[ "$1" == "unstack" ]]; then : fi if [[ "$1" == "clean" ]]; then # Remove state and transient data # Remember clean.sh first calls unstack.sh rm -f ${HORIZON_DIR}/openstack_dashboard/local/enabled/_1482_project_load_balancer_panel.py* rm -f ${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/_1499_load_balancer_settings.py* rm -f ${HORIZON_DIR}/openstack_dashboard/conf/octavia_policy.yaml fi fi ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/devstack/settings0000664000175100017510000000005615033037474020600 0ustar00mylesmylesOCTAVIA_DASHBOARD_DIR=$DEST/octavia-dashboard ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4641008 octavia_dashboard-15.1.0.dev2/doc/0000775000175100017510000000000015033037476015757 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/doc/requirements.txt0000664000175100017510000000027615033037474021246 0ustar00mylesmylesopenstackdocstheme>=2.2.1 # Apache-2.0 sphinx>=2.0.0 # BSD sphinxcontrib-apidoc>=0.2.1 # BSD # releasenotes reno>=3.1.0 # Apache-2.0 # PDF Docs sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4641008 octavia_dashboard-15.1.0.dev2/doc/source/0000775000175100017510000000000015033037476017257 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/doc/source/conf.py0000664000175100017510000001142115033037474020553 0ustar00mylesmyles# -*- coding: utf-8 -*- # 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 datetime import logging import os import sys import django sys.path.insert(0, os.path.abspath('../..')) sys.path.insert(0, os.path.abspath('.')) logging.getLogger('openstack_dashboard.settings').setLevel(logging.ERROR) os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'openstack_dashboard.settings') django.setup() # -- 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 = [ 'openstackdocstheme', 'sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinxcontrib.apidoc', 'sphinxcontrib.rsvgconverter' ] # autodoc generation is a bit aggressive and a nuisance when doing heavy # text edit cycles. # execute "export SPHINX_DEBUG=1" in your terminal to disable # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. copyright = '2017-2019, OpenStack Foundation' # 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 # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'native' # openstackdocstheme options openstackdocs_repo_name = 'openstack/octavia-dashboard' openstackdocs_pdf_link = True openstackdocs_use_storyboard = True apidoc_output_dir = 'contributor/modules' apidoc_module_dir = '../../octavia_dashboard' apidoc_excluded_paths = [ 'tests', 'enabled', 'locale', 'static', 'conf', 'local_settings.d', 'post_install.sh', 'karma.conf.js' ] # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. # html_theme_path = ["."] # html_theme = '_theme' # html_static_path = ['static'] html_theme = 'openstackdocs' html_theme_options = { 'show_other_versions': True } html_static_path = [] # Output file base name for HTML help builder. htmlhelp_basename = 'octavia-dashboarddoc' # A list of ignored prefixes for module index sorting. modindex_common_prefix = ['octavia-dashboard.'] # -- Options for LaTeX output ------------------------------------------------- # Fix Unicode character for sphinx_feature_classification # Sphinx default latex engine (pdflatex) doesn't know much unicode latex_preamble = r""" \usepackage{newunicodechar} \newunicodechar{✖}{\sffamily X} \setcounter{tocdepth}{2} \authoraddress{\textcopyright %s OpenStack Foundation} """ % datetime.datetime.now().year 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. # openany: Skip blank pages in generated PDFs 'extraclassoptions': 'openany,oneside', 'makeindex': '', 'printindex': '', 'preamble': latex_preamble } # Disable usage of xindy https://bugzilla.redhat.com/show_bug.cgi?id=1643664 # Some distros are missing xindy latex_use_xindy = False # Fix missing apostrophe smartquotes_excludes = {'builders': ['latex']} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [( 'index', 'doc-octavia-dashboard.tex', 'Octavia Dashboard Documentation', 'OpenStack Octavia Team', '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 = False ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/doc/source/contributing.rst0000664000175100017510000000011315033037474022511 0ustar00mylesmyles============ Contributing ============ .. include:: ../../CONTRIBUTING.rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/doc/source/index.rst0000664000175100017510000000062615033037474021122 0ustar00mylesmyles.. octavia-dashboard documentation master file, created by sphinx-quickstart on Tue Jul 9 22:26:36 2013. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to octavia-dashboard's documentation! ============================================= .. toctree:: :maxdepth: 2 readme installation contributing reference ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/doc/source/installation.rst0000664000175100017510000000200315033037474022503 0ustar00mylesmyles============ Installation ============ At the command line:: $ pip install octavia-dashboard Or, if you have virtualenvwrapper installed:: $ mkvirtualenv octavia-dashboard $ pip install octavia-dashboard To enable the panels in Horizon, copy _1482_project_load_balancer_panel.py in octavia_dashboard/enabled directory to openstack_dashboard/local/enabled (Optional) To enable policy enforcement at the Horizon level, copy the policy file into horizon's policy files folder, and add this config ``POLICY_FILES``:: 'octavia': 'octavia_policy.json', Django has a compressor feature that performs many enhancements for the delivery of static files. If the compressor feature is enabled in your environment (``COMPRESS_OFFLINE = True``), run the following commands:: $ ./manage.py collectstatic $ ./manage.py compress Finally restart your web server to enable octavia-dashboard in your Horizon: Ubuntu:: $ sudo service apache2 restart Red Hat based:: $ sudo systemctl restart httpd ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/doc/source/readme.rst0000664000175100017510000000003615033037474021243 0ustar00mylesmyles.. include:: ../../README.rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/doc/source/reference.rst0000664000175100017510000000042615033037474021747 0ustar00mylesmyles========= Reference ========= .. only:: latex Module Reference ---------------- .. toctree:: :hidden: contributor/modules/modules .. only:: html Indices and search ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/manage.py0000664000175100017510000000150715033037474017015 0ustar00mylesmyles#!/usr/bin/env python3 # 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 import sys from django.core.management import execute_from_command_line # noqa if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "openstack_dashboard.settings") execute_from_command_line(sys.argv) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4641008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/0000775000175100017510000000000015033037476020647 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/__init__.py0000664000175100017510000000120715033037474022756 0ustar00mylesmyles# 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__ = pbr.version.VersionInfo( 'octavia_dashboard').version_string() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/api/0000775000175100017510000000000015033037476021420 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/api/__init__.py0000664000175100017510000000000015033037474023515 0ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/api/rest/0000775000175100017510000000000015033037476022375 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/api/rest/__init__.py0000664000175100017510000000206215033037474024504 0ustar00mylesmyles# Copyright 2015 IBM Corp. # # 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 package holds the REST API that supports the Octavia dashboard Javascript code. It is not intended to be used outside of Horizon, and makes no promises of stability or fitness for purpose outside of that scope. It does not promise to adhere to the general OpenStack API Guidelines set out in https://wiki.openstack.org/wiki/APIChangeGuidelines. """ # import REST API modules here from octavia_dashboard.api.rest import barbican # noqa from octavia_dashboard.api.rest import lbaasv2 # noqa ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/api/rest/barbican.py0000664000175100017510000000331515033037474024510 0ustar00mylesmyles# Copyright 2016 IBM Corp. # # 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. """API over the barbican service. """ from django.views import generic from octavia_dashboard.sdk_connection import get_sdk_connection from openstack_dashboard.api.rest import urls from openstack_dashboard.api.rest import utils as rest_utils @urls.register class SSLCertificates(generic.View): """API for working with SSL certificate containers. """ url_regex = r'octavia-barbican/certificates/$' @rest_utils.ajax() def get(self, request): """List certificate containers. The listing result is an object with property "items". """ conn = get_sdk_connection(request) containers = list(conn.key_manager.containers( type='certificate')) return {'items': containers} @urls.register class Secrets(generic.View): """API for working with secrets. """ url_regex = r'octavia-barbican/secrets/$' @rest_utils.ajax() def get(self, request): """List secrets. The listing result is an object with property "items". """ conn = get_sdk_connection(request) secrets = list(conn.key_manager.secrets()) return {'items': secrets} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/api/rest/lbaasv2.py0000664000175100017510000014001015033037474024273 0ustar00mylesmyles# Copyright 2015 IBM Corp. # # 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. """API over the neutron LBaaS v2 service. """ import _thread as thread import time from django.views import generic from horizon import conf from octavia_dashboard.sdk_connection import get_sdk_connection from openstack import exceptions from openstack_dashboard.api import neutron from openstack_dashboard.api.rest import urls from openstack_dashboard.api.rest import utils as rest_utils neutronclient = neutron.neutronclient def _sdk_object_to_list(object): """Converts an SDK generator object to a list of dictionaries. :param object: SDK generator object :returns: List of dictionaries """ result_list = [] for item in object: result_list.append(_get_sdk_object_dict(item)) return result_list def _get_sdk_object_dict(object): """Converts an SDK object to a dictionary. Fixes any SDK imposed object oddities. :param object: SDK object :returns: Dictionary """ item_dict = object.to_dict() if 'is_admin_state_up' in item_dict: item_dict['admin_state_up'] = item_dict['is_admin_state_up'] return item_dict def poll_loadbalancer_status(request, loadbalancer_id, callback, from_state='PENDING_UPDATE', to_state='ACTIVE', callback_kwargs=None): """Poll for the status of the load balancer. Polls for the status of the load balancer and calls a function when the status changes to a specified state. :param request: django request object :param loadbalancer_id: id of the load balancer to poll :param callback: function to call when polling is complete :param from_state: initial expected state of the load balancer :param to_state: state to check for :param callback_kwargs: kwargs to pass into the callback function """ interval = conf.HORIZON_CONFIG['ajax_poll_interval'] / 1000.0 status = from_state while status == from_state: time.sleep(interval) conn = get_sdk_connection(request) lb = conn.load_balancer.get_load_balancer(loadbalancer_id) status = lb.provisioning_status if status == to_state: kwargs = {'loadbalancer_id': loadbalancer_id} if callback_kwargs: kwargs.update(callback_kwargs) callback(request, **kwargs) def _retry_on_conflict(conn, func, *args, retry_timeout=120, **kwargs): load_balancer_getter = kwargs.pop('load_balancer_getter') resource_id = kwargs.pop('resource_id') interval = conf.HORIZON_CONFIG['ajax_poll_interval'] / 1000.0 load_balancer_id = load_balancer_getter(conn, resource_id) start = time.time() while time.time() - start < retry_timeout: lb = conn.load_balancer.get_load_balancer(load_balancer_id) if lb.provisioning_status == 'PENDING_UPDATE': time.sleep(interval) continue try: func(*args, **kwargs) except exceptions.ConflictException: # Still catching 409/Conflict as there might have multiple threads # waiting for a non-PENDING provisioning state time.sleep(interval) continue break def retry_on_conflict(conn, func, *args, retry_timeout=120, **kwargs): load_balancer_getter = kwargs.pop('load_balancer_getter') resource_id = kwargs.pop('resource_id') try: func(*args, **kwargs) except exceptions.ConflictException: thread.start_new_thread( _retry_on_conflict, (conn, func, *args), {'retry_timeout': retry_timeout, 'load_balancer_getter': load_balancer_getter, 'resource_id': resource_id, **kwargs}) def listener_get_load_balancer_id(conn, listener_id): listener = conn.load_balancer.get_listener(listener_id) return listener.load_balancers[0]['id'] def l7_policy_get_load_balancer_id(conn, l7_policy_id): l7_policy = conn.load_balancer.get_l7_policy(l7_policy_id) listener = conn.load_balancer.get_listener(l7_policy.listener_id) return listener.load_balancers[0]['id'] def pool_get_load_balancer_id(conn, pool_id): pool = conn.load_balancer.get_pool(pool_id) return pool.loadbalancers[0]['id'] def health_monitor_get_load_balancer_id(conn, health_monitor_id): pool_id = conn.load_balancer.get_health_monitor(health_monitor_id) return pool_get_load_balancer_id(conn, pool_id) def create_loadbalancer(request): data = request.DATA conn = get_sdk_connection(request) build_kwargs = dict( project_id=request.user.project_id, vip_subnet_id=data['loadbalancer']['vip_subnet_id'], name=data['loadbalancer'].get('name'), description=data['loadbalancer'].get('description'), vip_address=data['loadbalancer'].get('vip_address'), admin_state_up=data['loadbalancer'].get('admin_state_up'), ) flavor_id = data['loadbalancer'].get('flavor_id') if flavor_id: build_kwargs['flavor_id'] = flavor_id availability_zone = data['loadbalancer'].get('availability_zone') if availability_zone: build_kwargs['availability_zone'] = availability_zone loadbalancer = conn.load_balancer.create_load_balancer(**build_kwargs) if data.get('listener'): # There is work underway to add a new API to LBaaS v2 that will # allow us to pass in all information at once. Until that is # available we use a separate thread to poll for the load # balancer status and create the other resources when it becomes # active. args = (request, loadbalancer.id, create_listener) kwargs = {'from_state': 'PENDING_CREATE'} thread.start_new_thread(poll_loadbalancer_status, args, kwargs) return _get_sdk_object_dict(loadbalancer) def create_listener(request, **kwargs): """Create a new listener. """ data = request.DATA try: default_tls_ref = data['certificates'][0] except (KeyError, IndexError): default_tls_ref = None conn = get_sdk_connection(request) # TODO(johnsom) Add SNI support # https://bugs.launchpad.net/octavia/+bug/1714294 listener = conn.load_balancer.create_listener( protocol=data['listener']['protocol'], protocol_port=data['listener']['protocol_port'], load_balancer_id=kwargs['loadbalancer_id'], name=data['listener'].get('name'), description=data['listener'].get('description'), connection_limit=data['listener'].get('connection_limit'), default_tls_container_ref=default_tls_ref, sni_container_refs=None, admin_state_up=data['listener'].get('admin_state_up'), insert_headers=data['listener'].get('insert_headers'), timeout_client_data=data['listener'].get('timeout_client_data'), timeout_member_connect=data['listener'].get('timeout_member_connect'), timeout_member_data=data['listener'].get('timeout_member_data'), timeout_tcp_inspect=data['listener'].get('timeout_tcp_inspect'), allowed_cidrs=data['listener'].get('allowed_cidrs'), # Replace empty string by None (uses default tls cipher string) tls_ciphers=data['listener'].get('tls_ciphers') or None, ) if data.get('pool'): args = (request, kwargs['loadbalancer_id'], create_pool) kwargs = {'callback_kwargs': {'listener_id': listener.id}} thread.start_new_thread(poll_loadbalancer_status, args, kwargs) return _get_sdk_object_dict(listener) def create_l7_policy(request, **kwargs): """Create a new l7 policy. """ data = request.DATA conn = get_sdk_connection(request) l7_policy = conn.load_balancer.create_l7_policy( action=data['l7policy']['action'], admin_state_up=data['l7policy'].get('admin_state_up'), description=data['l7policy'].get('description'), listener_id=kwargs['listener_id'], name=data['l7policy'].get('name'), position=data['l7policy'].get('position'), redirect_pool_id=data['l7policy'].get('redirect_pool_id'), redirect_url=data['l7policy'].get('redirect_url'), ) return _get_sdk_object_dict(l7_policy) def create_l7_rule(request, **kwargs): """Create a new l7 rule. """ data = request.DATA conn = get_sdk_connection(request) l7_rule = conn.load_balancer.create_l7_rule( admin_state_up=data['l7rule'].get('admin_state_up'), compare_type=data['l7rule']['compare_type'], invert=data['l7rule'].get('invert'), key=data['l7rule'].get('key'), l7_policy=kwargs['l7_policy_id'], type=data['l7rule']['type'], rule_value=data['l7rule']['rule_value'], ) return _get_sdk_object_dict(l7_rule) def create_pool(request, **kwargs): """Create a new pool. """ data = request.DATA conn = get_sdk_connection(request) pool = conn.load_balancer.create_pool( protocol=data['pool']['protocol'], lb_algorithm=data['pool']['lb_algorithm'], session_persistence=data['pool'].get('session_persistence'), listener_id=kwargs['listener_id'], loadbalancer_id=kwargs['loadbalancer_id'], name=data['pool'].get('name'), description=data['pool'].get('description'), admin_state_up=data['pool'].get('admin_state_up'), tls_enabled=data['pool'].get('tls_enabled'), # Replace empty string by None (uses default tls cipher string) tls_ciphers=data['pool'].get('tls_ciphers') or None, ) if data.get('members'): args = (request, kwargs['loadbalancer_id'], add_member) kwargs = {'callback_kwargs': {'pool_id': pool.id, 'index': 0}} thread.start_new_thread(poll_loadbalancer_status, args, kwargs) elif data.get('monitor'): args = (request, kwargs['loadbalancer_id'], create_health_monitor) kwargs = {'callback_kwargs': {'pool_id': pool.id}} thread.start_new_thread(poll_loadbalancer_status, args, kwargs) return _get_sdk_object_dict(pool) def create_health_monitor(request, **kwargs): """Create a new health monitor for a pool. """ data = request.DATA conn = get_sdk_connection(request) health_mon = conn.load_balancer.create_health_monitor( type=data['monitor']['type'], delay=data['monitor']['delay'], timeout=data['monitor']['timeout'], max_retries=data['monitor']['max_retries'], max_retries_down=data['monitor']['max_retries_down'], pool_id=kwargs['pool_id'], http_method=data['monitor'].get('http_method'), url_path=data['monitor'].get('url_path'), expected_codes=data['monitor'].get('expected_codes'), admin_state_up=data['monitor'].get('admin_state_up'), name=data['monitor'].get('name') ) return _get_sdk_object_dict(health_mon) def create_flavor(request, **kwargs): """Create a new flavor. """ data = request.DATA conn = get_sdk_connection(request) flavor = conn.load_balancer.create_flavor( name=data['flavor']['name'], flavor_profile_id=data['flavor']['flavor_profile_id'], description=data['flavor'].get('description'), enabled=data['flavor'].get('enabled'), ) return _get_sdk_object_dict(flavor) def create_flavor_profile(request, **kwargs): """Create a new flavor profile. """ data = request.DATA conn = get_sdk_connection(request) flavor_profile = conn.load_balancer.create_flavor( name=data['flavor_profile']['name'], provider_name=data['flavor_profile']['provider_name'], flavor_data=data['flavor_profile']['flavor_data'], ) return _get_sdk_object_dict(flavor_profile) def add_member(request, **kwargs): """Add a member to a pool. """ data = request.DATA members = data.get('members') pool_id = kwargs.get('pool_id') if kwargs.get('members_to_add'): members_to_add = kwargs['members_to_add'] index = [members.index(member) for member in members if member['id'] == members_to_add[0]][0] loadbalancer_id = data.get('loadbalancer_id') else: index = kwargs.get('index') loadbalancer_id = kwargs.get('loadbalancer_id') member = members[index] conn = get_sdk_connection(request) monitor_address = member.get('monitor_address') member = conn.load_balancer.create_member( pool_id, address=member['address'], protocol_port=member['protocol_port'], subnet_id=member['subnet_id'], weight=member.get('weight'), monitor_address=monitor_address if monitor_address else None, monitor_port=member.get('monitor_port'), admin_state_up=member.get('admin_state_up'), backup=member.get('backup', False), name=member.get('name'), ) index += 1 if kwargs.get('members_to_add'): args = (request, loadbalancer_id, update_member_list) members_to_add = kwargs['members_to_add'] members_to_add.pop(0) kwargs = {'callback_kwargs': { 'existing_members': kwargs.get('existing_members'), 'members_to_add': members_to_add, 'members_to_delete': kwargs.get('members_to_delete'), 'pool_id': pool_id}} thread.start_new_thread(poll_loadbalancer_status, args, kwargs) elif len(members) > index: args = (request, loadbalancer_id, add_member) kwargs = {'callback_kwargs': {'pool_id': pool_id, 'index': index}} thread.start_new_thread(poll_loadbalancer_status, args, kwargs) elif data.get('monitor'): args = (request, loadbalancer_id, create_health_monitor) kwargs = {'callback_kwargs': {'pool_id': pool_id}} thread.start_new_thread(poll_loadbalancer_status, args, kwargs) return _get_sdk_object_dict(member) def remove_member(request, **kwargs): """Remove a member from the pool. """ data = request.DATA loadbalancer_id = data.get('loadbalancer_id') pool_id = kwargs.get('pool_id') if kwargs.get('members_to_delete'): members_to_delete = kwargs['members_to_delete'] member_id = members_to_delete.pop(0) conn = get_sdk_connection(request) conn.load_balancer.delete_member(member_id, pool_id, ignore_missing=True) args = (request, loadbalancer_id, update_member_list) kwargs = {'callback_kwargs': { 'existing_members': kwargs.get('existing_members'), 'members_to_add': kwargs.get('members_to_add'), 'members_to_delete': members_to_delete, 'pool_id': pool_id}} thread.start_new_thread(poll_loadbalancer_status, args, kwargs) def update_loadbalancer(request, **kwargs): """Update a load balancer. """ data = request.DATA loadbalancer_id = kwargs.get('loadbalancer_id') conn = get_sdk_connection(request) loadbalancer = conn.load_balancer.update_load_balancer( loadbalancer_id, name=data['loadbalancer'].get('name'), description=data['loadbalancer'].get('description'), admin_state_up=data['loadbalancer'].get('admin_state_up')) return _get_sdk_object_dict(loadbalancer) def update_listener(request, **kwargs): """Update a listener. """ data = request.DATA listener_id = data['listener'].get('id') loadbalancer_id = data.get('loadbalancer_id') default_pool_id = data['listener'].get('default_pool_id') if not default_pool_id: default_pool_id = None else: default_pool_id = default_pool_id[:36] try: default_tls_ref = data['certificates'][0] except (KeyError, IndexError): default_tls_ref = None conn = get_sdk_connection(request) listener = conn.load_balancer.update_listener( listener=listener_id, name=data['listener'].get('name'), description=data['listener'].get('description'), connection_limit=data['listener'].get('connection_limit'), default_tls_container_ref=default_tls_ref, sni_container_refs=None, admin_state_up=data['listener'].get('admin_state_up'), default_pool_id=default_pool_id, insert_headers=data['listener'].get('insert_headers'), timeout_client_data=data['listener'].get('timeout_client_data'), timeout_member_connect=data['listener'].get('timeout_member_connect'), timeout_member_data=data['listener'].get('timeout_member_data'), timeout_tcp_inspect=data['listener'].get('timeout_tcp_inspect'), allowed_cidrs=data['listener'].get('allowed_cidrs'), # Replace empty string by None (uses default tls cipher string) tls_ciphers=data['listener'].get('tls_ciphers') or None, ) if data.get('pool'): args = (request, loadbalancer_id, update_pool) thread.start_new_thread(poll_loadbalancer_status, args) return _get_sdk_object_dict(listener) def update_l7_policy(request, **kwargs): """Update a l7 policy. """ data = request.DATA l7_policy_id = data['l7policy'].get('id') conn = get_sdk_connection(request) l7_policy = conn.load_balancer.update_l7_policy( action=data['l7policy']['action'], admin_state_up=data['l7policy'].get('admin_state_up'), description=data['l7policy'].get('description'), l7_policy=l7_policy_id, name=data['l7policy'].get('name'), position=data['l7policy'].get('position'), redirect_pool_id=data['l7policy'].get('redirect_pool_id'), redirect_url=data['l7policy'].get('redirect_url'), ) return _get_sdk_object_dict(l7_policy) def update_l7_rule(request, **kwargs): """Update a l7 rule. """ data = request.DATA l7_rule_id = data['l7rule'].get('id') conn = get_sdk_connection(request) l7_rule = conn.load_balancer.update_l7_rule( admin_state_up=data['l7rule'].get('admin_state_up'), compare_type=data['l7rule']['compare_type'], invert=data['l7rule'].get('invert'), key=data['l7rule'].get('key'), l7_policy=kwargs['l7_policy_id'], l7rule=l7_rule_id, type=data['l7rule']['type'], rule_value=data['l7rule']['rule_value'], ) return _get_sdk_object_dict(l7_rule) def update_pool(request, **kwargs): """Update a pool. """ data = request.DATA pool_id = data['pool'].get('id') loadbalancer_id = data.get('loadbalancer_id') conn = get_sdk_connection(request) pool = conn.load_balancer.update_pool( pool=pool_id, lb_algorithm=data['pool']['lb_algorithm'], session_persistence=data['pool'].get('session_persistence'), name=data['pool'].get('name'), description=data['pool'].get('description'), admin_state_up=data['pool'].get('admin_state_up'), tls_enabled=data['pool'].get('tls_enabled'), # Replace empty string by None (uses default tls cipher string) tls_ciphers=data['pool'].get('tls_ciphers') or None, ) # Assemble the lists of member id's to add and remove, if any exist request_member_data = data.get('members', []) existing_members = _sdk_object_to_list(conn.load_balancer.members(pool_id)) (members_to_add, members_to_delete) = get_members_to_add_remove( request_member_data, existing_members) if members_to_add or members_to_delete: args = (request, loadbalancer_id, update_member_list) kwargs = {'callback_kwargs': {'existing_members': existing_members, 'members_to_add': members_to_add, 'members_to_delete': members_to_delete, 'pool_id': pool_id}} thread.start_new_thread(poll_loadbalancer_status, args, kwargs) elif data.get('monitor'): args = (request, loadbalancer_id, update_monitor) thread.start_new_thread(poll_loadbalancer_status, args) return _get_sdk_object_dict(pool) def update_monitor(request, **kwargs): """Update a health monitor. """ data = request.DATA monitor_id = data['monitor']['id'] hm_type = data['monitor']['type'] conn = get_sdk_connection(request) healthmonitor_kwargs = { 'delay': data['monitor'].get('delay'), 'timeout': data['monitor'].get('timeout'), 'max_retries': data['monitor'].get('max_retries'), 'max_retries_down': data['monitor'].get('max_retries_down'), 'admin_state_up': data['monitor'].get('admin_state_up'), 'name': data['monitor'].get('name') } if hm_type in ('HTTP', 'HTTPS'): healthmonitor_kwargs.update({ 'http_method': data['monitor'].get('http_method'), 'url_path': data['monitor'].get('url_path'), 'expected_codes': data['monitor'].get('expected_codes') }) healthmonitor = conn.load_balancer.update_health_monitor( monitor_id, **healthmonitor_kwargs ) return _get_sdk_object_dict(healthmonitor) def update_flavor(request, **kwargs): """Update a flavor. """ data = request.DATA flavor_id = data['flavor']['id'] conn = get_sdk_connection(request) flavor = conn.load_balancer.update_flavor( flavor_id, name=data['flavor'].get('name'), description=data['flavor'].get('description'), enabled=data['flavor'].get('enabled'), ) return _get_sdk_object_dict(flavor) def update_flavor_profile(request, **kwargs): """Update a flavor profile. """ data = request.DATA flavor_profile_id = data['flavor_profile']['id'] conn = get_sdk_connection(request) flavor_profile = conn.load_balancer.update_flavor_profile( flavor_profile_id, name=data['flavor_profile'].get('name'), provider_name=data['flavor_profile'].get('provider_name'), flavor_data=data['flavor_profile'].get('flavor_data'), ) return _get_sdk_object_dict(flavor_profile) def update_member_list(request, **kwargs): """Update the list of members by adding or removing the necessary members. """ data = request.DATA loadbalancer_id = data.get('loadbalancer_id') pool_id = kwargs.get('pool_id') existing_members = kwargs.get('existing_members') members_to_add = kwargs.get('members_to_add') members_to_delete = kwargs.get('members_to_delete') if members_to_delete: kwargs = {'existing_members': existing_members, 'members_to_add': members_to_add, 'members_to_delete': members_to_delete, 'pool_id': pool_id} remove_member(request, **kwargs) elif members_to_add: kwargs = {'existing_members': existing_members, 'members_to_add': members_to_add, 'members_to_delete': members_to_delete, 'pool_id': pool_id} add_member(request, **kwargs) elif data.get('monitor'): args = (request, loadbalancer_id, update_monitor) thread.start_new_thread(poll_loadbalancer_status, args) def get_members_to_add_remove(request_member_data, existing_members): new_member_ids = [member['id'] for member in request_member_data] existing_member_ids = [member['id'] for member in existing_members] members_to_add = [member_id for member_id in new_member_ids if member_id not in existing_member_ids] members_to_delete = [member_id for member_id in existing_member_ids if member_id not in new_member_ids] return members_to_add, members_to_delete def add_floating_ip_info(request, loadbalancers): """Add floating IP address info to each load balancer. """ floating_ips = neutron.tenant_floating_ip_list(request) for lb in loadbalancers: floating_ip = {} associated_ip = next((fip for fip in floating_ips if fip['port_id'] == lb['vip_port_id']), None) if associated_ip is not None: floating_ip['id'] = associated_ip['id'] floating_ip['ip'] = associated_ip['ip'] lb['floating_ip'] = floating_ip @urls.register class LoadBalancers(generic.View): """API for load balancers. """ url_regex = r'lbaas/loadbalancers/$' @rest_utils.ajax() def get(self, request): """List load balancers for current project. The listing result is an object with property "items". """ conn = get_sdk_connection(request) lb_list = _sdk_object_to_list(conn.load_balancer.load_balancers( project_id=request.user.project_id)) if request.GET.get('full') and neutron.floating_ip_supported(request): add_floating_ip_info(request, lb_list) return {'items': lb_list} @rest_utils.ajax() def post(self, request): """Create a new load balancer. Creates a new load balancer as well as other optional resources such as a listener, pool, monitor, etc. """ return create_loadbalancer(request) @urls.register class LoadBalancer(generic.View): """API for retrieving, updating, and deleting a single load balancer. """ url_regex = r'lbaas/loadbalancers/(?P[^/]+)/$' @rest_utils.ajax() def get(self, request, loadbalancer_id): """Get a specific load balancer. http://localhost/api/lbaas/loadbalancers/cc758c90-3d98-4ea1-af44-aab405c9c915 """ conn = get_sdk_connection(request) loadbalancer = conn.load_balancer.find_load_balancer(loadbalancer_id) loadbalancer_dict = _get_sdk_object_dict(loadbalancer) if request.GET.get('full') and neutron.floating_ip_supported(request): add_floating_ip_info(request, [loadbalancer_dict]) return loadbalancer_dict @rest_utils.ajax() def put(self, request, loadbalancer_id): """Edit a load balancer. """ kwargs = {'loadbalancer_id': loadbalancer_id} update_loadbalancer(request, **kwargs) @rest_utils.ajax() def delete(self, request, loadbalancer_id): """Delete a specific load balancer. http://localhost/api/lbaas/loadbalancers/cc758c90-3d98-4ea1-af44-aab405c9c915 """ conn = get_sdk_connection(request) conn.load_balancer.delete_load_balancer(loadbalancer_id, ignore_missing=True, cascade=True) @urls.register class Listeners(generic.View): """API for load balancer listeners. """ url_regex = r'lbaas/listeners/$' @rest_utils.ajax() def get(self, request): """List of listeners for the current project. The listing result is an object with property "items". """ loadbalancer_id = request.GET.get('loadbalancerId') conn = get_sdk_connection(request) listener_list = _sdk_object_to_list(conn.load_balancer.listeners( project_id=request.user.project_id)) if loadbalancer_id: listener_list = self._filter_listeners(listener_list, loadbalancer_id) return {'items': listener_list} @rest_utils.ajax() def post(self, request): """Create a new listener. Creates a new listener as well as other optional resources such as a pool, members, and health monitor. """ kwargs = {'loadbalancer_id': request.DATA.get('loadbalancer_id')} return create_listener(request, **kwargs) def _filter_listeners(self, listener_list, loadbalancer_id): filtered_listeners = [] for listener in listener_list: if listener['load_balancers'][0]['id'] == loadbalancer_id: filtered_listeners.append(listener) return filtered_listeners @urls.register class Listener(generic.View): """API for retrieving, updating, and deleting a single listener. """ url_regex = r'lbaas/listeners/(?P[^/]+)/$' @rest_utils.ajax() def get(self, request, listener_id): """Get a specific listener. If the param 'includeChildResources' is passed in as a truthy value, the details of all resources that exist under the listener will be returned along with the listener details. http://localhost/api/lbaas/listeners/cc758c90-3d98-4ea1-af44-aab405c9c915 """ conn = get_sdk_connection(request) listener = conn.load_balancer.find_listener(listener_id) listener = _get_sdk_object_dict(listener) if request.GET.get('includeChildResources'): resources = {} resources['listener'] = listener if listener.get('default_pool_id'): pool_id = listener['default_pool_id'] pool = conn.load_balancer.find_pool(pool_id) pool = _get_sdk_object_dict(pool) resources['pool'] = pool if pool.get('members'): member_list = _sdk_object_to_list( conn.load_balancer.members(pool_id)) resources['members'] = member_list if pool.get('health_monitor_id'): monitor_id = pool['health_monitor_id'] monitor = conn.load_balancer.find_health_monitor( monitor_id) monitor = _get_sdk_object_dict(monitor) resources['monitor'] = monitor return resources else: return listener @rest_utils.ajax() def put(self, request, listener_id): """Edit a listener as well as any resources below it. """ kwargs = {'listener_id': listener_id} update_listener(request, **kwargs) @rest_utils.ajax() def delete(self, request, listener_id): """Delete a specific listener. http://localhost/api/lbaas/listeners/cc758c90-3d98-4ea1-af44-aab405c9c915 """ conn = get_sdk_connection(request) retry_on_conflict( conn, conn.load_balancer.delete_listener, listener_id, ignore_missing=True, load_balancer_getter=listener_get_load_balancer_id, resource_id=listener_id) @urls.register class L7Policies(generic.View): """API for load balancer l7 policies. """ url_regex = r'lbaas/l7policies/$' @rest_utils.ajax() def get(self, request): """List of l7 policies for the current project. The listing result is an object with property "items". """ listener_id = request.GET.get('listenerId') conn = get_sdk_connection(request) l7_policy_list = _sdk_object_to_list(conn.load_balancer.l7_policies( listener_id=listener_id)) return {'items': l7_policy_list} @rest_utils.ajax() def post(self, request): """Create a new l7 policy. Creates a new l7 policy as well as other optional resources such as l7 rules. """ kwargs = {'listener_id': request.DATA.get('parentResourceId')} return create_l7_policy(request, **kwargs) @urls.register class L7Policy(generic.View): """API for retrieving a single l7 policy. """ url_regex = r'lbaas/l7policies/(?P[^/]+)/$' @rest_utils.ajax() def get(self, request, l7_policy_id): """Get a specific l7 policy. If the param 'includeChildResources' is passed in as a truthy value, the details of all resources that exist under the l7 policy will be returned along with the l7 policy details. http://localhost/api/lbaas/l7policies/cc758c90-3d98-4ea1-af44-aab405c9c915 """ conn = get_sdk_connection(request) l7_policy = conn.load_balancer.find_l7_policy(l7_policy_id) l7_policy = _get_sdk_object_dict(l7_policy) if request.GET.get('includeChildResources'): resources = {} if l7_policy.get('rules'): l7_rules_list = _sdk_object_to_list( conn.load_balancer.l7_rules(l7_policy_id)) l7_policy['rules'] = l7_rules_list resources['l7policy'] = l7_policy return resources else: return l7_policy @rest_utils.ajax() def put(self, request, l7_policy_id): """Edit a l7 policy as well as any resources below it. """ kwargs = {'l7_policy_id': l7_policy_id} update_l7_policy(request, **kwargs) @rest_utils.ajax() def delete(self, request, l7_policy_id): """Delete a specific l7 policy. http://localhost/api/lbaas/l7policies/cc758c90-3d98-4ea1-af44-aab405c9c915 """ conn = get_sdk_connection(request) retry_on_conflict( conn, conn.load_balancer.delete_l7_policy, l7_policy_id, load_balancer_getter=l7_policy_get_load_balancer_id, resource_id=l7_policy_id) @urls.register class L7Rules(generic.View): """API for load balancer l7 rules. """ url_regex = r'lbaas/l7policies/(?P[^/]+)/l7rules/$' @rest_utils.ajax() def get(self, request, l7_policy_id): """List of l7 rules for the current project. The listing result is an object with property "items". """ conn = get_sdk_connection(request) l7_rule_list = _sdk_object_to_list(conn.load_balancer.l7_rules( l7_policy_id)) return {'items': l7_rule_list} @rest_utils.ajax() def post(self, request, l7_policy_id): """Create a new l7 rule. Creates a new l7 rule as well as other optional resources such as l7 rules. """ kwargs = {'l7_policy_id': l7_policy_id} return create_l7_rule(request, **kwargs) @urls.register class L7Rule(generic.View): """API for retrieving a single l7 rule. """ url_regex = ( r'lbaas/l7policies/(?P[^/]+)' r'/l7rules/(?P[^/]+)/$' ) @rest_utils.ajax() def get(self, request, l7_rule_id, l7_policy_id): """Get a specific l7 rule.""" conn = get_sdk_connection(request) l7_rule = conn.load_balancer.find_l7_rule(l7_rule_id, l7_policy_id) return _get_sdk_object_dict(l7_rule) @rest_utils.ajax() def put(self, request, l7_rule_id, l7_policy_id): """Edit a specific l7 rule.""" kwargs = {'l7_rule_id': l7_rule_id, 'l7_policy_id': l7_policy_id} update_l7_rule(request, **kwargs) @rest_utils.ajax() def delete(self, request, l7_rule_id, l7_policy_id): """Delete a specific l7 rule.""" conn = get_sdk_connection(request) retry_on_conflict( conn, conn.load_balancer.delete_l7_rule, l7_rule_id, l7_policy_id, load_balancer_getter=l7_policy_get_load_balancer_id, resource_id=l7_policy_id) @urls.register class Pools(generic.View): """API for load balancer pools. """ url_regex = r'lbaas/pools/$' @rest_utils.ajax() def get(self, request): """List of pools for the current project. The listing result is an object with property "items". """ loadbalancer_id = request.GET.get('loadbalancerId') listener_id = request.GET.get('listenerId') conn = get_sdk_connection(request) pool_list = _sdk_object_to_list(conn.load_balancer.pools( project_id=request.user.project_id)) if loadbalancer_id or listener_id: pool_list = self._filter_pools(pool_list, loadbalancer_id, listener_id) return {'items': pool_list} @rest_utils.ajax() def post(self, request): """Create a new pool. Creates a new pool as well as other optional resources such as members and health monitor. """ kwargs = {'loadbalancer_id': request.DATA.get('loadbalancer_id'), 'listener_id': request.DATA.get('parentResourceId')} return create_pool(request, **kwargs) def _filter_pools(self, pool_list, loadbalancer_id, listener_id): filtered_pools = [] for pool in pool_list: if loadbalancer_id: if pool['loadbalancers'][0]['id'] == loadbalancer_id: if listener_id: if (pool['listeners'] and pool['listeners'][0]['id'] == listener_id): filtered_pools.append(pool) else: filtered_pools.append(pool) elif (pool['listeners'] and pool['listeners'][0]['id'] == listener_id): filtered_pools.append(pool) return filtered_pools @urls.register class Pool(generic.View): """API for retrieving a single pool. """ url_regex = r'lbaas/pools/(?P[^/]+)/$' @rest_utils.ajax() def get(self, request, pool_id): """Get a specific pool. If the param 'includeChildResources' is passed in as a truthy value, the details of all resources that exist under the pool will be returned along with the pool details. http://localhost/api/lbaas/pools/cc758c90-3d98-4ea1-af44-aab405c9c915 """ conn = get_sdk_connection(request) pool = conn.load_balancer.find_pool(pool_id) pool = _get_sdk_object_dict(pool) if request.GET.get('includeChildResources'): resources = {} resources['pool'] = pool if pool.get('members'): member_list = _sdk_object_to_list( conn.load_balancer.members(pool_id)) resources['members'] = member_list if pool.get('health_monitor_id'): monitor_id = pool['health_monitor_id'] monitor = conn.load_balancer.find_health_monitor( monitor_id) monitor = _get_sdk_object_dict(monitor) resources['monitor'] = monitor return resources else: return pool @rest_utils.ajax() def put(self, request, pool_id): """Edit a listener as well as any resources below it. """ kwargs = {'pool_id': pool_id} update_pool(request, **kwargs) @rest_utils.ajax() def delete(self, request, pool_id): """Delete a specific pool. http://localhost/api/lbaas/pools/cc758c90-3d98-4ea1-af44-aab405c9c915 """ conn = get_sdk_connection(request) retry_on_conflict( conn, conn.load_balancer.delete_pool, pool_id, load_balancer_getter=pool_get_load_balancer_id, resource_id=pool_id) @urls.register class Members(generic.View): """API for load balancer members. """ url_regex = r'lbaas/pools/(?P[^/]+)/members/$' @rest_utils.ajax() def get(self, request, pool_id): """List of members for the current project. The listing result is an object with property "items". """ conn = get_sdk_connection(request) members_list = _sdk_object_to_list(conn.load_balancer.members(pool_id)) return {'items': members_list} @rest_utils.ajax() def put(self, request, pool_id): """Update the list of members for the current project. """ # Assemble the lists of member id's to add and remove, if any exist request_member_data = request.DATA.get('members', []) conn = get_sdk_connection(request) existing_members = _sdk_object_to_list( conn.load_balancer.members(pool_id)) (members_to_add, members_to_delete) = get_members_to_add_remove( request_member_data, existing_members) if members_to_add or members_to_delete: kwargs = {'existing_members': existing_members, 'members_to_add': members_to_add, 'members_to_delete': members_to_delete, 'pool_id': pool_id} update_member_list(request, **kwargs) @urls.register class Member(generic.View): """API for retrieving a single member. """ url_regex = r'lbaas/pools/(?P[^/]+)' + \ '/members/(?P[^/]+)/$' @rest_utils.ajax() def get(self, request, member_id, pool_id): """Get a specific member belonging to a specific pool. """ conn = get_sdk_connection(request) member = conn.load_balancer.find_member(member_id, pool_id) return _get_sdk_object_dict(member) @rest_utils.ajax() def delete(self, request, member_id, pool_id): """Delete a specific member belonging to a specific pool. """ conn = get_sdk_connection(request) retry_on_conflict( conn, conn.load_balancer.delete_member, member_id, pool_id, load_balancer_getter=pool_get_load_balancer_id, resource_id=pool_id) @rest_utils.ajax() def put(self, request, member_id, pool_id): """Edit a pool member. """ data = request.DATA conn = get_sdk_connection(request) monitor_address = data.get('monitor_address') member = conn.load_balancer.update_member( member_id, pool_id, weight=data.get('weight'), monitor_address=monitor_address if monitor_address else None, monitor_port=data.get('monitor_port'), admin_state_up=data.get('admin_state_up'), backup=data.get('backup', False), name=data.get('name'), ) return _get_sdk_object_dict(member) @urls.register class HealthMonitors(generic.View): """API for load balancer pool health monitors. """ url_regex = r'lbaas/healthmonitors/$' @rest_utils.ajax() def get(self, request): """List of health monitors for the current project. The listing result is an object with property "items". """ pool_id = request.GET.get('poolId') conn = get_sdk_connection(request) health_monitor_list = _sdk_object_to_list( conn.load_balancer.health_monitors( project_id=request.user.project_id ) ) if pool_id: health_monitor_list = self._filter_health_monitors( health_monitor_list, pool_id) return {'items': health_monitor_list} @rest_utils.ajax() def post(self, request): """Create a new health monitor. """ kwargs = {'loadbalancer_id': request.DATA.get('loadbalancer_id'), 'pool_id': request.DATA.get('parentResourceId')} return create_health_monitor(request, **kwargs) def _filter_health_monitors(self, health_monitor_list, pool_id): filtered_health_monitors = [] for health_monitor in health_monitor_list: if health_monitor['pools'][0]['id'] == pool_id: filtered_health_monitors.append(health_monitor) return filtered_health_monitors @urls.register class HealthMonitor(generic.View): """API for retrieving a single health monitor. """ url_regex = r'lbaas/healthmonitors/(?P[^/]+)/$' @rest_utils.ajax() def get(self, request, health_monitor_id): """Get a specific health monitor. """ conn = get_sdk_connection(request) health_mon = conn.load_balancer.find_health_monitor(health_monitor_id) return _get_sdk_object_dict(health_mon) @rest_utils.ajax() def delete(self, request, health_monitor_id): """Delete a specific health monitor. http://localhost/api/lbaas/healthmonitors/cc758c90-3d98-4ea1-af44-aab405c9c915 """ conn = get_sdk_connection(request) retry_on_conflict( conn, conn.load_balancer.delete_health_monitor, health_monitor_id, ignore_missing=True, load_balancer_getter=health_monitor_get_load_balancer_id, resource_id=health_monitor_id) @rest_utils.ajax() def put(self, request, health_monitor_id): """Edit a health monitor. """ update_monitor(request) @urls.register class Flavors(generic.View): """API for load balancer flavors. """ url_regex = r'lbaas/flavors/$' @rest_utils.ajax() def get(self, request): """List of flavors for the current project. The listing result is an object with property "items". """ conn = get_sdk_connection(request) flavor_list = _sdk_object_to_list( conn.load_balancer.flavors() ) return {'items': flavor_list} @rest_utils.ajax() def post(self, request): """Create a new flavor. """ kwargs = { 'flavor': request.DATA.get('flavor') } return create_flavor(request, **kwargs) @urls.register class Flavor(generic.View): """API for retrieving a single flavor. """ url_regex = r'lbaas/flavors/(?P[^/]+)/$' @rest_utils.ajax() def get(self, request, flavor_id): """Get a specific flavor. """ conn = get_sdk_connection(request) flavor = conn.load_balancer.find_flavor(flavor_id) return _get_sdk_object_dict(flavor) @rest_utils.ajax() def delete(self, request, flavor_id): """Delete a specific flavor. http://localhost/api/lbaas/flavors/3971d368-ca9b-4770-929a-3adca5bf89eb """ conn = get_sdk_connection(request) conn.load_balancer.delete_flavor(flavor_id, ignore_missing=True) @rest_utils.ajax() def put(self, request, flavor_id): """Edit a flavor. """ update_flavor(request) @urls.register class FlavorProfiles(generic.View): """API for load balancer flavor profiles. """ url_regex = r'lbaas/flavorprofiles/$' @rest_utils.ajax() def get(self, request): """List of flavor profiles for the current project. The listing result is an object with property "items". """ conn = get_sdk_connection(request) flavor_profile_list = _sdk_object_to_list( conn.load_balancer.flavor_profiles() ) return {'items': flavor_profile_list} @rest_utils.ajax() def post(self, request): """Create a new flavor_profile. """ kwargs = { 'flavor_profile': request.DATA.get('flavor_profile') } return create_flavor_profile(request, **kwargs) @urls.register class FlavorProfile(generic.View): """API for retrieving a single flavor profile. """ url_regex = r'lbaas/flavorprofiles/(?P[^/]+)/$' @rest_utils.ajax() def get(self, request, flavor_profile_id): """Get a specific flavor profile. """ conn = get_sdk_connection(request) flavor_profile = conn.load_balancer.find_flavor_profile( flavor_profile_id) return _get_sdk_object_dict(flavor_profile) @rest_utils.ajax() def delete(self, request, flavor_profile_id): """Delete a specific flavor profile. http://localhost/api/lbaas/flavorprofiles/e8150eab-aefa-42cc-867e-3fb336da52bd """ conn = get_sdk_connection(request) conn.load_balancer.delete_flavor_profile(flavor_profile_id, ignore_missing=True) @rest_utils.ajax() def put(self, request, flavor_profile_id): """Edit a flavor profile. """ update_flavor_profile(request) @urls.register class AvailabilityZones(generic.View): """API for load balancer availability zones. """ url_regex = r'lbaas/availabilityzones/$' @rest_utils.ajax() def get(self, request): """List of availability zones for the current project. The listing result is an object with property "items". """ conn = get_sdk_connection(request) availability_zone_list = _sdk_object_to_list( conn.load_balancer.availability_zones() ) return {'items': availability_zone_list} ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/conf/0000775000175100017510000000000015033037476021574 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/conf/.gitkeep0000664000175100017510000000000015033037474023211 0ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/0000775000175100017510000000000015033037476022761 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/__init__.py0000664000175100017510000000000015033037474025056 0ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/0000775000175100017510000000000015033037476024427 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/__init__.py0000664000175100017510000000000015033037474026524 0ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/0000775000175100017510000000000015033037476027175 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/__init__.py0000664000175100017510000000127115033037474031305 0ustar00mylesmyles# Copyright 2016 IBM Corp. # # 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. # Register the REST API URLs so they can be called from the JavaScript files from octavia_dashboard.api import rest # noqa ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/panel.py0000664000175100017510000000150715033037474030647 0ustar00mylesmyles# (c) Copyright 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. from django.utils.translation import gettext_lazy as _ import horizon class NGLoadBalancers(horizon.Panel): name = _("Load Balancers") slug = 'load_balancer' permissions = ('openstack.services.load-balancer',) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4521008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/templates/0000775000175100017510000000000015033037476031173 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00115 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/templates/load_balancer/ 28 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/templates/load_bala0000775000175100017510000000000015033037476033012 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/templates/load_balancer/index.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/templates/load_bala0000664000175100017510000000046415033037474033016 0ustar00mylesmyles{% extends 'base.html' %} {% load i18n %} {% block title %}{% trans "Load Balancers" %}{% endblock %} {% block page_header %}{% endblock %} {% block breadcrumb_nav %}{% endblock %} {% block ng_route_base %} {% endblock %} {% block main %}
{% endblock %} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/urls.py0000664000175100017510000000143215033037474030532 0ustar00mylesmyles# (c) Copyright 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. from django.urls import re_path from octavia_dashboard.dashboards.project.load_balancer import views urlpatterns = [ re_path('', views.IndexView.as_view(), name='index'), ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/dashboards/project/load_balancer/views.py0000664000175100017510000000142515033037474030704 0ustar00mylesmyles# (c) Copyright 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. from horizon.views import HorizonTemplateView class IndexView(HorizonTemplateView): template_name = 'project/load_balancer/index.html' page_title = 'Load Balancers' ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/enabled/0000775000175100017510000000000015033037476022241 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/enabled/_1482_project_load_balancer_panel.py0000664000175100017510000000225015033037474031100 0ustar00mylesmyles# Copyright 2015 IBM Corp. # # 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. # The slug of the panel to be added to HORIZON_CONFIG. Required. PANEL = 'load_balancer' # The slug of the dashboard the PANEL is associated with. Required. PANEL_DASHBOARD = 'project' # The slug of the panel group the PANEL is associated with. PANEL_GROUP = 'network' # Python panel class of the PANEL to be added. ADD_PANEL = ( 'octavia_dashboard.dashboards.project.load_balancer.panel' '.NGLoadBalancers') ADD_INSTALLED_APPS = ['octavia_dashboard'] ADD_ANGULAR_MODULES = ['horizon.dashboard.project.lbaasv2'] ADD_SCSS_FILES = ['dashboard/project/lbaasv2/lbaasv2.scss'] AUTO_DISCOVER_STATIC_FILES = True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/enabled/__init__.py0000664000175100017510000000000015033037474024336 0ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/karma.conf.js0000664000175100017510000001237415033037474023231 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ 'use strict'; var fs = require('fs'); var path = require('path'); module.exports = function (config) { // This tox venv is setup in the post-install npm step var toxPath = path.resolve('./.tox/karma'); if (!toxPath) { console.error('xStatic libraries not found, please run `tox -e karma`'); process.exit(1); } toxPath += '/lib/'; toxPath += fs.readdirSync(toxPath).find(function(directory) { return directory.indexOf('python') === 0; }); toxPath += '/site-packages/'; config.set({ preprocessors: { // Used to collect templates for preprocessing. // NOTE: the templates must also be listed in the files section below. './static/**/*.html': ['ng-html2js'], // Used to indicate files requiring coverage reports. './static/**/!(*.spec).js': ['coverage'], }, // Sets up module to process templates. ngHtml2JsPreprocessor: { prependPrefix: '/', moduleName: 'templates' }, basePath: './', // Contains both source and test files. files: [ /* * shim, partly stolen from /i18n/js/horizon/ * Contains expected items not provided elsewhere (dynamically by * Django or via jasmine template. */ '../test-shim.js', // from jasmine.html toxPath + 'xstatic/pkg/jquery/data/jquery.js', toxPath + 'xstatic/pkg/angular/data/angular.js', toxPath + 'xstatic/pkg/angular/data/angular-route.js', toxPath + 'xstatic/pkg/angular/data/angular-mocks.js', toxPath + 'xstatic/pkg/angular/data/angular-cookies.js', toxPath + 'xstatic/pkg/angular_bootstrap/data/angular-bootstrap.js', toxPath + 'xstatic/pkg/angular_gettext/data/angular-gettext.js', toxPath + 'xstatic/pkg/angular_fileupload/data/ng-file-upload-all.js', toxPath + 'xstatic/pkg/angular/data/angular-sanitize.js', toxPath + 'xstatic/pkg/d3/data/d3.js', toxPath + 'xstatic/pkg/rickshaw/data/rickshaw.js', toxPath + 'xstatic/pkg/angular_smart_table/data/smart-table.js', toxPath + 'xstatic/pkg/angular_lrdragndrop/data/lrdragndrop.js', toxPath + 'xstatic/pkg/angular_schema_form/data/schema-form.js', toxPath + 'xstatic/pkg/spin/data/spin.js', toxPath + 'xstatic/pkg/spin/data/spin.jquery.js', // TODO: These should be mocked. toxPath + '/horizon/static/horizon/js/horizon.js', /** * Include framework source code from horizon that we need. * Otherwise, karma will not be able to find them when testing. * These files should be mocked in the foreseeable future. */ toxPath + 'horizon/static/framework/**/*.module.js', toxPath + 'horizon/static/framework/**/!(*.spec|*.mock).js', toxPath + 'openstack_dashboard/static/**/*.module.js', toxPath + 'openstack_dashboard/static/**/!(*.spec|*.mock).js', toxPath + 'openstack_dashboard/dashboards/**/static/**/*.module.js', toxPath + 'openstack_dashboard/dashboards/**/static/**/!(*.spec|*.mock).js', /** * First, list all the files that defines application's angular modules. * Those files have extension of `.module.js`. The order among them is * not significant. */ './static/**/*.module.js', /** * Followed by other JavaScript files that defines angular providers * on the modules defined in files listed above. And they are not mock * files or spec files defined below. The order among them is not * significant. */ './static/**/!(*.spec|*.mock).js', /** * Then, list files for mocks with `mock.js` extension. The order * among them should not be significant. */ toxPath + 'openstack_dashboard/static/**/*.mock.js', //'./static/**/*.mock.js', /** * Finally, list files for spec with `spec.js` extension. The order * among them should not be significant. */ './static/**/*.spec.js', /** * Angular external templates */ './static/**/*.html' ], autoWatch: true, frameworks: ['jasmine'], browsers: ['Firefox'], reporters: ['progress', 'coverage', 'threshold'], plugins: [ 'karma-firefox-launcher', 'karma-jasmine', 'karma-ng-html2js-preprocessor', 'karma-coverage', 'karma-threshold-reporter' ], coverageReporter: { type: 'html', dir: '../cover/', subdir: '.', check: { global: { statements: 100, branches: 100, functions: 100, lines: 100 } } }, // Coverage threshold values. thresholdReporter: { statements: 100, branches: 100, functions: 100, lines: 100 } }); }; ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/local_settings.d/0000775000175100017510000000000015033037476024103 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py0000664000175100017510000000211515033037474031765 0ustar00mylesmyles# Copyright 2018 Walmart. # 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 to be included for configuring application which relates # to load-balancer(Octavia) functions. from django.conf import settings settings.POLICY_FILES.update({ 'load-balancer': 'octavia_policy.yaml', }) # Sample # settings.LOGGING['loggers'].update({ # 'openstack': { # 'handlers': ['console'], # 'level': 'DEBUG', # 'propagate': False, # }, # 'barbicanclient': { # 'handlers': ['console'], # 'level': 'DEBUG', # 'propagate': False, # } # }) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4541008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/0000775000175100017510000000000015033037476022106 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4521008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/de/0000775000175100017510000000000015033037476022476 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/de/LC_MESSAGES/0000775000175100017510000000000015033037476024263 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/de/LC_MESSAGES/django.po0000664000175100017510000000112215033037474026057 0ustar00mylesmyles# Frank Kloeker , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2018-02-04 12:30+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-02-02 10:13+0000\n" "Last-Translator: Frank Kloeker \n" "Language-Team: German\n" "Language: de\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "Load Balancers" msgstr "Loadbalancer" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/de/LC_MESSAGES/djangojs.po0000664000175100017510000012646515033037474026436 0ustar00mylesmyles# Andreas Jaeger , 2018. #zanata # Frank Kloeker , 2018. #zanata # Robert Simai , 2018. #zanata # Robert Simai , 2019. #zanata # Andreas Jaeger , 2020. #zanata # Robert Holling , 2022. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2022-08-16 20:34+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2022-04-06 10:34+0000\n" "Last-Translator: Robert Holling \n" "Language-Team: German\n" "Language: de\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #, python-format msgid "%(ip)s..." msgstr "%(ip)s..." msgid "A new health monitor is being created." msgstr "Ein neuer Gesundheitsmonitor wurde erstellt." msgid "A new l7 policy is being created." msgstr "Eine neue L7 Richtlinie wird erstellt." msgid "A new listener is being created." msgstr "Ein neuer Listener wird erstellt." msgid "A new load balancer is being created." msgstr "Ein neuer Loadbalancer wird erstellt." msgid "A new pool is being created." msgstr "Ein neuer Pool wird erstellt." msgid "" "A pool represents a group of members over which the load balancing will be " "applied." msgstr "" "Ein Pool repräsentiert eine Gruppe von Mitgliedern, auf die die " "Lastverteilung angewendet wird." msgid "APP_COOKIE: Session persistence based on application cookie." msgstr "APP_COOKIE: Sitzungsdauer basiert auf einen Anwendungs-Cookie." msgid "Action" msgstr "Aktion" msgid "Action:" msgstr "Aktion:" msgid "Active" msgstr "Aktiv" msgid "Add" msgstr "Hinzufügen" msgid "Add external member" msgstr "Externes Mitglied hinzufügen" msgid "Add members to the load balancer pool." msgstr "Mitglieder zum Loadbalancer-Pool hinzufügen." msgid "Add/Remove Members" msgstr "Hinzufügen/Löschen Mitglieder" msgid "Add/Remove Pool Members" msgstr "Pool-Mitglieder hinzufügen/entfernen" msgid "" "Additional headers insertion into HTTP header,\n" " only \"X-Forwarded-For\", \"X-Forwarded-Port\" and \"X-Forwarded-Proto\" " "are supported." msgstr "" "Einfügen zusätzlicher Headerzeilen in den HTTP Header. Es werden nur \"X-" "Forwarded-For\", \"X-Forwarded-Port\" und \"X-Forwarded-Proto\" unterstützt." msgid "Admin State Up" msgstr "Adminstatus aktiv" msgid "Algorithm" msgstr "Algorithmus" msgid "Algorithm:" msgstr "Algorithmus:" msgid "Allocated Members" msgstr "Zugewiesene Mitglieder" msgid "" "An L7 Policy is a collection of L7 rules associated with a Listener, and " "which may also have an association to a back-end pool" msgstr "" "Eine L7 Richtlinie ist eine Sammlung von L7 Regeln, die einem Listener " "zugewiesen sind und auch eine Zuordnung zu einem back-end Pool haben können." msgid "" "An L7 Rule is a single, simple logical test which returns either true or\n" "false." msgstr "" "Eine L7 Regel ist ein einfacher logischer Test, der richtig oder falsch " "zurückgibt." msgid "" "An alternate IP address used for health monitoring a backend member.\n" " Default is null which monitors the member address." msgstr "" "Eine alternative IP-Adresse für Gesundheitsmonitoring eines Backend-" "Mitglieds.\n" " Standard ist null wodurch zum Monitoren die Mitgliedadresse benutzt wird." msgid "" "An alternate protocol port used for health monitoring a backend member.\n" " Default is null which monitors the member protocol port." msgstr "" "Ein alternativer Protokoll-Port für Gesundheitsmonitoring eins Backend-" "Mitglieds.\n" " Standard ist null wodurch zum Monitoren der Mitgliedport benutzt wird." msgid "An error occurred. Please try again later." msgstr "Ein Fehler ist aufgetreten. Bitte versuchen Sie es später noch einmal." msgid "Associate" msgstr "Zuweisen" msgid "Associate Floating IP" msgstr "Floating IP zuweisen" msgid "Associate Floating IP Address" msgstr "Floating-IP-Adresse zuweisen" msgid "Associating floating IP with load balancer." msgstr "Floating-IP mit Loadbalancer verbinden." msgid "Availability Zone" msgstr "Verfügbarkeitszone" msgid "Available Instances" msgstr "Verfügbare Instanzen" msgid "Backend member connection timeout in milliseconds. Default: 5000." msgstr "Back-End-Mitgliedsverbindungs-Timeout in Millisekunden Standard: 5000." msgid "Backend member inactivity timeout in milliseconds. Default: 50000." msgstr "" "Inaktivitätszeitlimit des Back-End-Mitglieds in Millisekunden. Standard: " "50000." msgid "Backup" msgstr "Sicherungskopie" msgid "Backup:" msgstr "Sicherungskopie:" msgid "CIDR" msgstr "CIDR" msgid "CONTAINS: String contains." msgstr "CONTAINS: Zeichenkette enthält." msgid "" "COOKIE: The rule looks for a cookie named by the key parameter and\n" " compares it against the value parameter in the rule." msgstr "" "COOKIE: Die Regel sucht nach einem Cookie, das mit dem Schlüsselparameter " "benannt ist und\n" " vergleicht es mit dem Wertparameter in der Regel." msgid "Cancel" msgstr "Abbrechen" msgid "Certificate Name" msgstr "Zertifikatname" msgid "Client Data Timeout" msgstr "Client Data Timeout" msgid "Client Data Timeout:" msgstr "Client Data Timeout:" msgid "Compare Type" msgstr "Typ vergleichen" msgid "Compare Type:" msgstr "Vergleichstyp:" msgid "Confirm Delete Health Monitor" msgid_plural "Confirm Delete Health Monitors" msgstr[0] "Bestätigen Gesundheitsmonitor löschen" msgstr[1] "Bestätigen Gesundheitsmonitore löschen" msgid "Confirm Delete L7 Policy" msgid_plural "Confirm Delete L7 Policies" msgstr[0] "L7 Richtlinie löschen bestätigen" msgstr[1] "L7 Richtlinien löschen bestätigen" msgid "Confirm Delete L7 Rule" msgid_plural "Confirm Delete L7 Rules" msgstr[0] "L7 Regel löschen bestätigen" msgstr[1] "L7 Regeln löschen bestätigen" msgid "Confirm Delete Listener" msgid_plural "Confirm Delete Listeners" msgstr[0] "Listener löschen bestätigen" msgstr[1] "Listener löschen bestätigen" msgid "Confirm Delete Load Balancer" msgid_plural "Confirm Delete Load Balancers" msgstr[0] "Bestätigen Loadbalancer löschen" msgstr[1] "Bestätigen Loadbalancer löschen" msgid "Confirm Delete Member" msgid_plural "Confirm Delete Members" msgstr[0] "Bestätigen Mitglied löschen" msgstr[1] "Bestätigen Mitglieder löschen" msgid "Confirm Delete Pool" msgid_plural "Confirm Delete Pools" msgstr[0] "Bestätigen Pool löschen" msgstr[1] "Bestätigen Pools löschen" msgid "Confirm Disassociate Floating IP Address" msgstr "Ablösung der Floating-IP-Adresse bestätigen" msgid "Connection Limit" msgstr "Verbindungsgrenze" msgid "Connection Limit:" msgstr "Verbindungslimits:" msgid "Contains" msgstr "Enthält" msgid "Cookie" msgstr "Cookie" msgid "Cookie Name" msgstr "Cookie-Name" msgid "Create Health Monitor" msgstr "Gesundheitsmonitor erzeugen" msgid "Create L7 Policy" msgstr "L7 Richtlinie erstellen" msgid "Create L7 Rule" msgstr "L7 Regel erstellen" msgid "Create Listener" msgstr "Listener erstellen" msgid "Create Load Balancer" msgstr "Loadbalancer erstellen" msgid "Create Pool" msgstr "Pool erstellen" msgid "Created At" msgstr "Erstellt am" msgid "Default Pool ID" msgstr "Standard Pool-ID" msgid "Default Pool ID:" msgstr "Standard Pool ID:" msgid "Default TLS Container Ref" msgstr "Standard TLS Container Ref" msgid "Degraded" msgstr "Degradiert" msgid "Delay" msgstr "Verzögerung" msgid "Delay (sec)" msgstr "Verzögerung (Sek)" msgid "Delay:" msgstr "Verzögerung:" msgid "Delete Health Monitor" msgid_plural "Delete Health Monitors" msgstr[0] "Gesundheitsmonitor löschen" msgstr[1] "Gesundheitsmonitore löschen" msgid "Delete Health Monitors" msgstr "Gesundheitsmonitore löschen" msgid "Delete L7 Policies" msgstr "L7 Richtlinien löschen" msgid "Delete L7 Policy" msgid_plural "Delete L7 Policies" msgstr[0] "L7 Richtlinie löschen" msgstr[1] "L7 Richtlinien löschen" msgid "Delete L7 Rule" msgid_plural "Delete L7 Rules" msgstr[0] "L7 Regel löschen" msgstr[1] "L7 Regeln löschen" msgid "Delete L7 Rules" msgstr "L7 Regeln löschen" msgid "Delete Listener" msgid_plural "Delete Listeners" msgstr[0] "Listener löschen" msgstr[1] "Listener löschen" msgid "Delete Listeners" msgstr "Listener löschen" msgid "Delete Load Balancer" msgid_plural "Delete Load Balancers" msgstr[0] "Loadbalancer löschen" msgstr[1] "Loadbalancer löschen" msgid "Delete Load Balancers" msgstr "Loadbalancer löschen" msgid "Delete Member" msgid_plural "Delete Members" msgstr[0] "Mitglied löschen" msgstr[1] "Mitglieder löschen" msgid "Delete Members" msgstr "Mitglieder löschen" msgid "Delete Pool" msgid_plural "Delete Pools" msgstr[0] "Pool löschen" msgstr[1] "Pools löschen" msgid "Delete Pools" msgstr "Gelöschte Pools" #, python-format msgid "Deleted Health Monitor: %s." msgid_plural "Deleted Health Monitors: %s." msgstr[0] "Gelöschter Gesundheitsmonitor: %s." msgstr[1] "Gelöschte Gesundheitsmonitore: %s." #, python-format msgid "Deleted L7 Policy: %s." msgid_plural "Deleted L7 Policies: %s." msgstr[0] "Gelöschte L7 Richtlinie: %s." msgstr[1] "Gelöschte L7 Richtlinien: %s." #, python-format msgid "Deleted L7 Rule: %s." msgid_plural "Deleted L7 Rules: %s." msgstr[0] "Gelöschte L7 Regel: %s." msgstr[1] "Gelöschte L7 Regeln: %s." #, python-format msgid "Deleted Listener: %s." msgid_plural "Deleted Listeners: %s." msgstr[0] "Gelöschte Listener: %s." msgstr[1] "Gelöschte Listener: %s." #, python-format msgid "Deleted Load Balancer: %s." msgid_plural "Deleted Load Balancers: %s." msgstr[0] "Gelöschte Loadbalancer: %s." msgstr[1] "Gelöschte Loadbalancer: %s." #, python-format msgid "Deleted Member: %s." msgid_plural "Deleted Members: %s." msgstr[0] "Gelöschtes Mitglied: %s." msgstr[1] "Gelöschte Mitglieder: %s." #, python-format msgid "Deleted Pool: %s." msgid_plural "Deleted Pools: %s." msgstr[0] "Gelöschter Pool: %s." msgstr[1] "Gelöschte Pools: %s." msgid "Description" msgstr "Beschreibung" msgid "Disassociate" msgstr "Trennen" msgid "Disassociate Floating IP" msgstr "Floating IP trennen" #, python-format msgid "Disassociated floating IP address from load balancer: %s." msgstr "Verbindung der Floating-IP zum Loadbalancer lösen: %s." msgid "ENDS_WITH: String ends with." msgstr "ENDS_WITH: Zeichenkette endet damit." msgid "EQUAL_TO: String is equal to." msgstr "EQUAL_TO: Zeichenkette ist gleich." msgid "" "Each port that listens for traffic on a particular load balancer is " "configured separately and\n" " tied to the load balancer. Multiple listeners can be associated with the " "same load balancer but\n" " each must use a unique port." msgstr "" "Jeder Port, der an einem bestimmten Loadbalancer auf Datenverkehr wartet, " "wird separat konfiguriert und\n" " an den Loadbalancer gebunden. Multiple Listener können dem selben " "Loadbalancer zugewiesen werden aber\n" " jeder muss seinen einmaligen Port haben." msgid "Edit Health Monitor" msgstr "Gesundheitsmonitor bearbeiten" msgid "Edit L7 Policy" msgstr "L7 Richtlinie bearbeiten" msgid "Edit L7 Rule" msgstr "L7 Regel bearbeiten" msgid "Edit Listener" msgstr "Listener bearbeiten" msgid "Edit Load Balancer" msgstr "Loadbalancer bearbeiten" msgid "Edit Member" msgstr "Mitglied bearbeiten" msgid "Edit Pool" msgstr "Pool bearbeiten" msgid "Ends With" msgstr "Endet mit" msgid "Equal To" msgstr "Entspricht" msgid "Error" msgstr "Fehler" msgid "Expected Codes" msgstr "Erwartete Codes" msgid "Expected Codes:" msgstr "Erwartete Codes:" msgid "Expiration Date" msgstr "Ablaufdatum" msgid "" "FILE_TYPE: The rule compares the last portion of the URI against\n" " the value parameter in the rule. (eg. \"txt\", \"jpg\", etc.)" msgstr "" "FILE_TYPE: Die Regel vergleicht den letzten Teil des URIs mit\n" " der Wertparameter in der Regel (z.B. \"txt\", \"jpg\" usw.)" msgid "File Type" msgstr "Dateityp" msgid "Flavor" msgstr "Variante" msgid "Flavor Description" msgstr "Varianten-Beschreibung" msgid "Flavor ID" msgstr "Varianten-ID" msgid "Floating IP" msgstr "Floating IP" msgid "Floating IP address or pool" msgstr "Floating IP Addresse oder Pool" msgid "Floating IP addresses" msgstr "Floating-IP-Adressen" msgid "Floating IP pools" msgstr "Floating-IP-Pools" msgid "Frontend client inactivity timeout in milliseconds. Default: 50000." msgstr "" "Inaktivitätszeitlimit des Front-End-Clients in Millisekunden. Standard: " "50000." msgid "" "HEADER: The rule looks for a header defined in the key parameter\n" " and compares it against the value parameter in the rule." msgstr "" "HEADER: Die Regel sucht nach einem Header, der im Schlüsselparameter " "definiert ist\n" " und vergleicht sie mit dem Wertparameter in der Regel." msgid "" "HOST_NAME: The rule does a comparison between the HTTP/1.1\n" " hostname in the request against the value parameter in the rule." msgstr "" "HOST_NAME: Die Regel führt einen Vergleich zwischen HTTP/1.1 durch\n" " Hostname in der Anforderung für den Wertparameter in der Regel." msgid "HTTP Method" msgstr "HTTP-Methode" msgid "HTTP Method:" msgstr "HTTP Methode:" msgid "HTTP_COOKIE: Session persistence based on http cookie." msgstr "HTTP_COOKIE: Sitzungsdauer basiert auf HTTP-Cookie." msgid "Header" msgstr "Header" msgid "Health Monitor" msgstr "Gesundheitsmonitor" msgid "Health Monitor ID" msgstr "Gesundheitsmonitor-ID" msgid "Health Monitors" msgstr "Gesundheitsmonitore" msgid "Host Name" msgstr "Hostname" msgid "ID" msgstr "ID" msgid "IP Address" msgstr "IP-Adresse" #, python-format msgid "IP Addresses (%(count)s)" msgstr "IP-Adressen (%(count)s)" msgid "IP address" msgstr "IP-Adresse" msgid "IP address:" msgstr "IP-Adresse:" msgid "" "If an IP address is provided it must be a well-formed IPv4 or IPv6 address. " "The system will\n" " attempt to assign the provided IP address to the load balancer. If an IP " "address is not provided\n" " then one will be allocated for you." msgstr "" "Wenn eine IP-Adresse angegeben wird, muss dies in der bekannten IPv4 oder " "IPv6 Form geschehen. Das System wird\n" " versuchen, die bereitgestellte IP-Adresse zum Loadbalancer hinzuzufügen. " "Wenn keine IP-Adresse zur Verfügung gestellt ist,\n" " wird eine für Sie allokiert." msgid "" "If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL " "certificates must\n" " be selected. The first certificate will be the default." msgstr "" "Wenn der Listener das TERMINATED_HTTPS Protokoll verwendet, müssen ein oder " "mehrere Zertifikate ausgewählt sein.\n" " Das erste Zertifikat wird der Standard." msgid "Inactive" msgstr "Inaktiv" msgid "Insert Headers" msgstr "Kopfzeilen einfügen" msgid "Insert Headers:" msgstr "Header einfügen:" msgid "Invert" msgstr "Invertieren" msgid "Invert:" msgstr "Invertieren:" msgid "" "Is the member a backup? Backup members only receive traffic when all\n" " non-backup members are down." msgstr "" "Ist das Mitglied ein Backup? Backup-Mitglieder erhalten nur Datenverkehr, " "wenn alle vorhanden sind\n" " Nicht-Backup-Mitglieder sind nicht erreichbar." msgid "Key" msgstr "Schlüssel" msgid "Key Manager API Guide: Creating a Certificate Container" msgstr "Key Manager API Leitfaden: Erstellen eines Zertifikat-Containers" msgid "Key Manager Service Command-Line Client" msgstr "Key Manager Service Command-Line Client" msgid "Key:" msgstr "Schlüssel:" msgid "L7 Policies" msgstr "L7 Policies" msgid "L7 Policy" msgstr "L7 Richtlinie" msgid "L7 Policy Details" msgstr "L7 Richtlinie Details" msgid "L7 Rule" msgstr "L7 Regel" msgid "L7 Rule Details" msgstr "L7 Regel Details" msgid "L7 Rules" msgstr "L7 Regeln" msgid "" "LEAST_CONNECTIONS: Allocates requests to the instance with the least number " "of active\n" " connections." msgstr "" "LEAST_CONNECTIONS: Allokiert Anfragen zur Instanz mit den wenigsten aktiven\n" " Verbindungen." msgid "Least Connections" msgstr "Letzte Verbindungen" msgid "Listener" msgstr "Listener" msgid "Listener Details" msgstr "Listener Details" msgid "Listener ID" msgstr "Listener-ID" msgid "Listeners" msgstr "Listener" msgid "Load Balancer" msgstr "Loadbalancer" msgid "Load Balancer Details" msgstr "Loadbalancer-Details" msgid "Load Balancers" msgstr "Loadbalancer" msgid "Loading" msgstr "Ladevorgang" msgid "Max Retries" msgstr "Max Wiederholungen" msgid "Max Retries Down" msgstr "Max Wiederholungen herunter" msgid "Max Retries Down:" msgstr "Maximale Wiederholungen:" msgid "Max Retries:" msgstr "Max Versuche:" msgid "Member" msgstr "Mitglied" msgid "Member Connect Timeout" msgstr "Member Connect Timeout" msgid "Member Connect Timeout:" msgstr "Member Connect Timeout:" msgid "Member Data Timeout" msgstr "Member Data Timeout" msgid "Member Data Timeout:" msgstr "Member Data Timeout:" msgid "Members" msgstr "Mitglieder" msgid "" "Members are the actual IP addresses that will receive traffic from the load " "balancer. Each\n" " member must have a unique combination of IP address and port." msgstr "" "Mitglieder sind die aktuellen IP-Adressen, die Datenverkehr vom Loadbalancer " "empfangen. Jedes Mitglied\n" " muss eine einmalige Kombination aus IP-Adresse und Port haben." msgid "Monitor Address" msgstr "Monitor Addresse" msgid "Monitor Address:" msgstr "Monitor-Adresse:" msgid "Monitor Details" msgstr "Monitordetails" msgid "Monitor Port" msgstr "Monitor Port" msgid "Monitor Port:" msgstr "Monitor Port:" msgid "Name" msgstr "Name" msgid "Network" msgstr "Netzwerk" msgid "Network ID" msgstr "Netzwerk ID" msgid "No" msgstr "Nein" msgid "No Monitor" msgstr "Kein Monitor" msgid "No available certificates" msgstr "Keine Zertifikate verfügbar" msgid "No available instances" msgstr "Keine Instanzen verfügbar" msgid "No items to display." msgstr "Keine Einträge zum Anzeigen." msgid "No matching options" msgstr "Keine übereinstimmende Option" msgid "No members have been allocated" msgstr "Es wurden keine Mitglieder zugewiesen" msgid "None" msgstr "Keine" msgid "Offline" msgstr "Offline" msgid "Online" msgstr "Online" msgid "Operating Status" msgstr "Betriebsstatus" msgid "Overview" msgstr "Übersicht" msgid "" "PATH: The rule compares the path portion of the HTTP URI against\n" " the value parameter in the rule." msgstr "" "PATH: Die Regel vergleicht den Pfadabschnitt des HTTP-URIs mit\n" " der Wertparameter in der Regel" msgid "Path" msgstr "Pfad" msgid "Pending Create" msgstr "Geplante Erstellung" msgid "Pending Delete" msgstr "Geplante Löschung" msgid "Pending Update" msgstr "Geplante Aktualisierung" msgid "Please Wait" msgstr "Bitte warten" msgid "Pool" msgstr "Pool" msgid "Pool Details" msgstr "Pool-Details" msgid "Pool Members" msgstr "Pool-Mitglieder" msgid "Pool member has been updated." msgstr "Das Pool-Mitglied wurde aktualisiert." msgid "Pools" msgstr "Pool" msgid "Port" msgstr "Port" msgid "Port ID" msgstr "Port-ID" msgid "Port:" msgstr "Port:" msgid "Position" msgstr "Position" msgid "Position:" msgstr "Position:" msgid "Project" msgstr "Projekt" msgid "Project ID" msgstr "Projekt-ID" msgid "Protocol" msgstr "Protokoll" msgid "Protocol Port" msgstr "Protokollport" msgid "Protocol:" msgstr "Protokoll:" msgid "Provide the details for the health monitor." msgstr "Geben Sie die Details zum Gesundheitsmonitor an." msgid "Provide the details for the l7 policy." msgstr "Angabe von Details zur L7 Richtlinie." msgid "Provide the details for the l7 rule." msgstr "Angabe von Details zur L7 Regel." msgid "Provide the details for the listener." msgstr "Geben Sie die Details für den Listener an." msgid "Provide the details for the load balancer." msgstr "Geben Sie die Details zum Loadbalancer an." msgid "Provide the details for the member." msgstr "Details über das Mitglied zur Verfügung stellen." msgid "Provide the details for the pool." msgstr "Geben Sie die Details zum Pool an." msgid "Provider" msgstr "Anbieter" msgid "Provisioning Status" msgstr "Provisionierungsstatus" msgid "" "REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated " "with the L7 policy." msgstr "" "REDIRECT_TO_POOL: Die Anfrage wird an den mit der L7 Richtlinie verbundenen " "back-end Pool weitergeleitet." msgid "" "REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in " "the redirect_url parameter." msgstr "" "REDIRECT_TO_URL: Die Anfrage wird mit einer HTTP-Umleitung an die im " "redirect_url Parameter definierte URL beantwortet." msgid "REGEX: Perl type regular expression matching." msgstr "REGEX: Übereinstimmung mit Perl-typischem regulären Ausdrück." msgid "" "REJECT: The request is denied with an appropriate response code, and not " "forwarded on to any back-end pool." msgstr "" "REJECT: Die Anfrage wird mit einem angemessenen Antwortcode abgewiesen und " "nicht an einen back-end Pool weitergeleitet." msgid "ROUND_ROBIN: Rotates requests evenly between multiple instances." msgstr "" "ROUND_ROBIN: Rotiert Anfragen zufällig zwischen verschiedenen Instanzen." msgid "Redirect Pool ID" msgstr "Umleitungs-Pool-ID" msgid "Redirect Pool ID:" msgstr "Redirect Pool ID:" msgid "Redirect URL" msgstr "Umleitungs-URL" msgid "Redirect URL:" msgstr "Redirect URL:" msgid "Redirect to Pool" msgstr "Zu Pool umleiten" msgid "Redirect to URL" msgstr "Zu URL umleiten" msgid "Regex" msgstr "Regex" msgid "Reject" msgstr "Abweisen" msgid "Remove" msgstr "Entfernen" msgid "" "Requests matching this policy will be redirected to the pool with this ID. " "Only valid if action is REDIRECT_TO_POOL." msgstr "" "Anfragen, die der Richtlinie entsprechen, werden an den Pool mit dieser ID " "weitergeleitet. Nur gültig, wenn die Aktion REDIRECT_TO_POOL gesetzt ist." msgid "" "Requests matching this policy will be redirected to this URL. Only valid if " "action is REDIRECT_TO_URL." msgstr "" "Anfragen, die der Richtlinie entsprechen, werden zu dieser URL " "weitergeleitet. Nur gültig, wenn die Aktion REDIRECT_TO_URL gesetzt ist." msgid "Round Robin" msgstr "Rundlauf-Verfahren" msgid "Rules" msgstr "Regeln" msgid "SNI Container Refs" msgstr "SNI Container Refs" msgid "" "SOURCE_IP: Requests from a unique source IP address are consistently " "directed to the same instance." msgstr "" "SOURCE_IP: Anfragen von derselben Quell-IP-Adresse werden permanent zur " "selben Instanz geschickt." msgid "SOURCE_IP: Session persistence based on source ip." msgstr "SOURCE_IP: Sitzungsdauer basiert auf Quell-IP." msgid "SSL Certificates" msgstr "SSL-Zertifikate" msgid "STARTS_WITH: String starts with." msgstr "STARTS_WITH: Zeichenkette startet damit." msgid "" "Select a floating IP address to associate with the load balancer or a " "floating IP pool in which to allocate a new floating IP address." msgstr "" "Wählen Sie eine Floating-IP-Adresse, um sie dem Loadbalancer zuzuweisen, " "oder einen Floating-IP-Pool, in welchem eine Floating-IP-Adresse belegt " "werden kann." msgid "Select certificates from the available certificates below" msgstr "" "Wählen Sie Zertifikate aus den unten stehenden verfügbaren Zertifikaten aus" msgid "Select one or more SSL certificates for the listener." msgstr "Wählen Sie ein oder mehrere Zertifikate für den Listener." msgid "Session Persistence" msgstr "Sitzungspersistenz" msgid "Session Persistence:" msgstr "Sitzungsdauer:" msgid "Source IP" msgstr "Quell-IP" msgid "Starts With" msgstr "Beginnt mit" msgid "Subnet" msgstr "Teilnetz" msgid "Subnet ID" msgstr "Subnetz-ID" msgid "Subnet:" msgstr "Teilnetz:" msgid "TCP Inspect Timeout" msgstr "Auszeit" msgid "TCP Inspect Timeout:" msgstr "TCP Inspect Timeout:" msgid "" "The Available Instances table contains existing compute instances that can " "be added as members\n" " of the pool. Use the \"Add external member\" button to add a member not " "found in the Available\n" " Instances table." msgstr "" "Die Tabelle Verfügbare Instanzen enthält existierende Compute Instanzen, die " "als Mitglieder des Pools hinzugefügt werden \n" "können. Verwenden Sie \"Externes Mitglied hinzufügen\", um ein Mitglied " "hinzuzufügen, dass sich nicht in der Tabelle \n" "befindet." msgid "The HTTP method used to perform the health check." msgstr "" "Die HTTP-Methode die zur Durchführung des Gesundheitchecks angewendet wird." msgid "The ID of the pool used by the listener if no L7 policies match." msgstr "" "Die ID des vom Listener verwendeten Pools, wenn keine L7-Richtlinien " "übereinstimmen." msgid "The IP address is not valid." msgstr "Die IP-Adresse ist ungültig." msgid "" "The IP address of the member to receive traffic from the load balancer. Must " "be a well-formed\n" " IPv4 or IPv6 address." msgstr "" "Die IP-Addresse des Mitglieds, der den Verkehr vom Loadbalancer erhält. Muss " "im bekannten Format sein als\n" " IPv4 oder IPv6 Addresse." msgid "" "The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL." msgstr "" "Die L7 Richtlinienaktion. Eine von REJECT, REDIRECT_TO_URL oder " "REDIRECT_TO_POOL." msgid "The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH." msgstr "" "Der L7 Regeltyp. Einer aus COOKIE, FILE_TYPE, HEADER, HOST_NAME oder PATH." msgid "The URL path is not valid." msgstr "Der URL-Pfad ist ungültig." msgid "" "The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, or STARTS_WITH." msgstr "" "Der Vergleichstyp für die L7-Regel. Eine von CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, or STARTS_WITH." msgid "The connection limit must be a number greater than or equal to -1." msgstr "Das Verbindungslimit muss eine Nummer grösser oder gleich -1 sein." msgid "" "The expected HTTP status codes to get from a successful health check. Must " "be a single number,\n" " a comma separated list of numbers, or a range (two numbers separated by a " "hyphen)." msgstr "" "Der erwartete HTTP Status-Code welcher vom erfolgreichen Gesundheitscheck " "zurückgeliefert wird. Muss eine einfache Zahl sein,\n" " eine kommaseparierte Liste von Zahlen oder ein Bereich (2 Zahlen separiert " "von einem Bindestrich)." msgid "The expected status code is not valid." msgstr "Der erwartete Statuscode ist ungültig." msgid "The health check interval must be greater than or equal to the timeout." msgstr "" "Das Gesundheitscheck-Intervall muss größer oder gleich dem Zeitlimit sein." msgid "The health monitor has been updated." msgstr "Der Gesundheitsmonitor wurde aktualisiert." msgid "" "The health monitor is used to determine the health of your pool members. " "Health checks\n" " routinely run against each member within the pool and the result of the " "health check is used\n" " to determine if the member receives new connections. Each pool can only " "have one health\n" " monitor." msgstr "" "Der Gesundheitsmonitor wird verwendet, um den Zustand Ihrer Pool-Mitglieder " "zu bestimmen. Gesundheitschecks\n" " laufen routinemäßig für alle Mitglieder im Pool und das Ergebnis\n" " wird verwendet um zu bestimmen, \n" "ob das Mitglied neue Verbindungen empfängt. Jeder Pool kann seinen eigenen " "Gesundheitsmonitor haben." msgid "" "The interval between health checks. Must be greater than or equal to the " "timeout." msgstr "" "Das Intervall zwischen Gesundheitschecks. Muss groesser oder gleich dem " "Timeout sein." msgid "" "The key to use for the comparison. For example, the name of the cookie\n" " to evaluate." msgstr "" "Der Schlüssel zum Vergleich. Zum Beispiel der Name des Cookies\n" " zur Evaluierung." msgid "The l7policy has been updated." msgstr "Die L7 Richtlinie wurde aktualisiert." msgid "The l7rule has been updated." msgstr "Die L7 Regel wurde aktualisiert." msgid "The listener has been updated." msgstr "Der Listener wurde aktualisiert." msgid "" "The load balancer algorithm that distributes traffic to the pool members." msgstr "" "Der L oadbalancer-Algorithmus zum Verteilen der Anfragen auf die Pool-" "Mitglieder." msgid "The load balancer has been updated." msgstr "Der Loadbalancer wurde aktualisiert." msgid "" "The load balancer occupies a neutron network port and has an IP address " "assigned from a subnet." msgstr "" "Der Loadbalancer belegt einen Neutron-Port und bekommt eine IP-Adresse aus " "einem Subnetz zugewiesen." msgid "The max retry count must be a number between 1 and 10." msgstr "Die maximale Wiederholungszahl muss eine Zahl zwischen 1 und 10 sein." msgid "The max retry down count must be a number between 1 and 10." msgstr "Die Zahl maximaler Wiederholungen muss zwischen 1 und 10 liegen." msgid "" "The maximum number of connections permitted for this listener.\n" " Default value is -1 which represents infinite connections." msgstr "" "Die maximale Anzahl von erlaubten Verbindungen für den Listener.\n" " Standardwert ist -1 was eine unbegrenzte Anzahl darstellt." msgid "The monitor address must be a valid IP address." msgstr "Die Monitoradresse muss eine gültige IP-Adresse sein." msgid "The monitor port must be a number between 1 and 65535." msgstr "Der Monitor Port muss eine Nummer zwischen 1 und 65535 sein." msgid "The network on which to allocate the load balancer's IP address." msgstr "" "Das Netzwerk in welchem sich die IP-Adresse des Loadbalancers befindet." msgid "The network which contains the IP address of the member." msgstr "Das Netzwerk in welchem sich die IP-Adresse des Mitglieds befindet." msgid "" "The number of allowed connection failures before marking the member as " "error. Must be a\n" " number from 1 to 10. The default is 3." msgstr "" "Die Anzahl der erlaubten Verbindungsfehlern bevor das Mitglied als " "fehlerhaft markiert wird. Muss eine\n" " Nummer von 1 bis 10 sein. Der Standard ist 3." msgid "" "The number of allowed connection failures before marking the member as " "inactive. Must be a\n" " number from 1 to 10." msgstr "" "Die Anzahl der erlaubten Verbindungsfehlern bevor das Mitglied als inaktiv " "markiert wird. Muss eine\n" " Nummer von 1 bis 10 sein." msgid "The pool has been updated." msgstr "Der Pool wurde aktualisiert." msgid "The pool members have been updated." msgstr "Die Pool-Mitglieder wurden aktualisiert." msgid "The port must be a number between 1 and 65535." msgstr "Der Port muss eine Zahl zwischen 1 und 65535 sein." msgid "" "The port must be unique among all listeners attached to this load balancer." msgstr "" "Der Port muss über alle Listener, die diesem Loadbalancer zugewiesen sind, " "einmalig sein. " msgid "" "The port on which the front end listens. Must be an integer from 1 to 65535." msgstr "Der Port an dem das Frontend hört. Muss integer von 1 zu 65535 sein." msgid "" "The port on which the member listens for traffic. Must be a number from 1 to " "65535." msgstr "" "Der Port auf dem das Mitglied auf den Verkehr hört. Muss eine Zahl zwischen " "1 und 65535 sein." msgid "The position must be a number between 1 and 2147483647." msgstr "Die Position muss eine Zahl zwischen 1 und 2147483647 sein." msgid "The position of this policy on the listener. Positions start at 1." msgstr "Die Position der Richtlinie im Listener. Die Positionen starten bei 1." msgid "" "The protocol for which the front end listens. The TERMINATED_HTTPS protocol " "is only available if\n" " the key-manager service is enabled and you have authority to list " "certificate containers and\n" " secrets." msgstr "" "Das Protokoll auf dem das Frontend hört. Das TERMINATED_HTTPS Protokoll ist " "nur verfügbar wenn\n" " der Schlüsselverwaltungsdienst aktiviert ist und Sie die Berechtigung " "haben, Zertifikats-Container und Geheimnisse aufzulisten." msgid "The redirect url must be a valid http or https url." msgstr "Die Umleitungs-URL muss eine gültige http oder https URL sein." msgid "" "The target of the health check HTTP request to the member. Must be a valid " "URL path." msgstr "" "Das Ziel des HTTP-Requests des Gesundheitschecks. Muss ein gültiger URL-Pfad " "sein." msgid "" "The time after which a health check times out. Must be a number greater than " "or equal to 0\n" " and less than or equal to the interval." msgstr "" "Die Zeit nachdem ein Gesundheitscheck eine Auszeit nimmt. Muss eine Nummer " "groesser oder gleich 0 sein\n" " und kleiner oder gleich zum Intervall." msgid "The timeout must be a number between 0 and 31536000000." msgstr "Das Zeitlimit muss eine Zahl zwischen 0 und 31536000000 sein." msgid "The timeout must be a number greater than or equal to 0." msgstr "Das Zeitlimit muss eine Zahl größer oder gleich 0 sein." msgid "" "The type of session persistence for distributing traffic to the pool members." msgstr "" "Der Typ der Sitzungsdauer für Verkehrsverteilung zwischen den " "Poolmitgliedern." msgid "" "The value to use for the comparison. For example, the file type to compare." msgstr "Der Schlüssel zum Vergleich. Zum Beispiel der Dateityp zum Vergleich." msgid "" "Time, in milliseconds, to wait for additional TCP packets for content\n" " inspection. Default: 0." msgstr "" "Zeit in Millisekunden, um auf zusätzliche TCP-Pakete für den Inhalt zu " "warten\n" " Inspektion. Standard: 0." msgid "Timeout" msgstr "Zeitlimit" msgid "Timeout (sec)" msgstr "Timeout (sek)" msgid "Timeout:" msgstr "Timeout:" msgid "Type" msgstr "Typ" msgid "Type:" msgstr "Typ:" msgid "URL Path" msgstr "URL Pfad" msgid "URL Path:" msgstr "URL-Pfad:" msgid "Unable to create flavor profile." msgstr "Das Varianten-Profil konnte nicht erstellt werden." msgid "Unable to create flavor." msgstr "Variante kann nicht erstellt werden." msgid "Unable to create health monitor." msgstr "Gesundheitsmonitor kann nicht erzeugt werden." msgid "Unable to create l7 policy." msgstr "L7 Richtlinie kann nicht erstellt werden." msgid "Unable to create l7 rule." msgstr "L7 Regel kann nicht erstellt werden." msgid "Unable to create listener." msgstr "Listener kann nicht erstellt werden" msgid "Unable to create load balancer." msgstr "Loadbalancer kann nicht erstellt werden." msgid "Unable to create pool." msgstr "Pool kann nicht erzeugt werden." #, python-format msgid "Unable to delete Health Monitor: %s." msgid_plural "Unable to delete Health Monitors: %s." msgstr[0] "Konnte Gesundheitsmonitor nicht löschen: %s." msgstr[1] "Konnte Gesundheitsmonitore nicht löschen: %s." #, python-format msgid "Unable to delete L7 Policy: %s." msgid_plural "Unable to delete L7 Policies: %s." msgstr[0] "L7 Richtlinie kann nicht gelöscht werden: %s." msgstr[1] "L7 Richtlinien können nicht gelöscht werden: %s." #, python-format msgid "Unable to delete L7 Rule: %s." msgid_plural "Unable to delete L7 Rules: %s." msgstr[0] "L7 Regel kann nicht gelöscht werden: %s." msgstr[1] "L7 Regeln können nicht gelöscht werden: %s." #, python-format msgid "Unable to delete Listener: %s." msgid_plural "Unable to delete Listeners: %s." msgstr[0] "Konnte Listener nicht löschen: %s." msgstr[1] "Konnte Listener nicht löschen: %s." #, python-format msgid "Unable to delete Load Balancer: %s." msgid_plural "Unable to delete Load Balancers: %s." msgstr[0] "Konnte Loadbalancer nicht löschen: %s." msgstr[1] "Konnte Loadbalancer nicht löschen: %s." #, python-format msgid "Unable to delete Member: %s." msgid_plural "Unable to delete Members: %s." msgstr[0] "Konnte Mitglied nicht löschen: %s." msgstr[1] "Konnte Mitglieder nicht löschen: %s." #, python-format msgid "Unable to delete Pool: %s." msgid_plural "Unable to delete Pools: %s." msgstr[0] "Konnte Pool nicht löschen: %s." msgstr[1] "Konnte Pools nicht löschen: %s." msgid "Unable to delete flavor profile." msgstr "Das Varianten-Profil kann nicht gelöscht werden." msgid "Unable to delete flavor." msgstr "Variante kann nicht gelöscht werden." msgid "Unable to delete health monitor." msgstr "Gesundheitsmonitor kann nicht gelöscht werden." msgid "Unable to delete l7 policy." msgstr "L7 Richtlinie kann nicht gelöscht werden." msgid "Unable to delete l7 rule." msgstr "L7 Regel kann nicht gelöscht werden." msgid "Unable to delete listener." msgstr "Listener kann nicht gelöscht werden." msgid "Unable to delete load balancer." msgstr "Loadbalancer kann nicht gelöscht werden." msgid "Unable to delete member." msgstr "Mitglied kann nicht gelöscht werden." msgid "Unable to delete pool." msgstr "Pool kann nicht gelöscht werden." #, python-format msgid "Unable to disassociate floating IP address from load balancer: %s." msgstr "" "Verbindung der Floating-IP zum Loadbalancer kann nicht gelöst werden: %s." msgid "Unable to retrieve SSL certificates." msgstr "SSL-Zertifikate können nicht abgerufen werden." msgid "Unable to retrieve availability zones." msgstr "Verfügbarkeitszonen können nicht abgerufen werden." msgid "Unable to retrieve flavor profile." msgstr "Das Varianten-Profil kann nicht abgerufen werden." msgid "Unable to retrieve flavor profiles." msgstr "Die Varianten-Profile können nicht abgerufen werden." msgid "Unable to retrieve flavor." msgstr "Die Variante kann nicht abgerufen werden." msgid "Unable to retrieve flavors." msgstr "Varianten können nicht abgerufen werden." msgid "Unable to retrieve health monitor." msgstr "Gesundheitsmonitor kann nicht abgerufen werden." msgid "Unable to retrieve health monitors." msgstr "Gesundheitsmonitore können nicht abgerufen werden." msgid "Unable to retrieve l7 policies." msgstr "L7 Richtlinien können nicht abgerufen werden." msgid "Unable to retrieve l7 policy." msgstr "L7 Richtlinie kann nicht abgerufen werden." msgid "Unable to retrieve l7 rule." msgstr "L7 Regel kann nicht abgerufen werden." msgid "Unable to retrieve l7 rules." msgstr "L7 Regeln können nicht abgerufen werden." msgid "Unable to retrieve listener." msgstr "Listener kann nicht abgerufen werden." msgid "Unable to retrieve listeners." msgstr "Listener können nicht abgerufen werden." msgid "Unable to retrieve load balancer." msgstr "Loadbalancer kann nicht abgerufen werden." msgid "Unable to retrieve load balancers." msgstr "Loadbalancer können nicht abgerufen werden." msgid "Unable to retrieve member." msgstr "Mitglied kann nicht abgerufen werden." msgid "Unable to retrieve members." msgstr "Mitglieder können nicht abgerufen werden." msgid "Unable to retrieve pool." msgstr "Pool kann nicht abgerufen werden." msgid "Unable to retrieve pools." msgstr "Pools können nicht abgerufen werden." msgid "Unable to retrieve secrets." msgstr "Geheimdaten können nicht abgerufen werden." msgid "Unable to update flavor profile." msgstr "Das Varianten-Profil konnte nicht aktualisiert werden." msgid "Unable to update flavor." msgstr "Die Variante kann nicht aktualisiert werden." msgid "Unable to update health monitor." msgstr "Gesundheitsmonitor kann nicht aktualisiert werden." msgid "Unable to update l7 policy." msgstr "L7 Richtlinie kann nicht aktualisiert werden." msgid "Unable to update l7 rule." msgstr "L7 Regel kann nicht aktualisiert werden." msgid "Unable to update listener." msgstr "Listener kann nicht aktualisiert werden." msgid "Unable to update load balancer." msgstr "Loadbalancer kann nicht aktualisiert werden." msgid "Unable to update member list." msgstr "Mitgliederliste kann nicht aktualisiert werden." msgid "Unable to update member." msgstr "Mitglied kann nicht aktualisiert werden." msgid "Unable to update pool." msgstr "Pool kann nicht aktualisiert werden." msgid "Update" msgstr "Aktualisieren" msgid "Update Health Monitor" msgstr "Gesundheitsmonitor aktualisieren" msgid "Update L7 Policy" msgstr "L7 Richtlinie aktualisieren" msgid "Update L7 Rule" msgstr "L7 Regel aktualisieren" msgid "Update Listener" msgstr "Listener aktualisieren" msgid "Update Load Balancer" msgstr "Loadbalancer aktualisieren" msgid "Update Member" msgstr "Mitglied aktualisieren" msgid "Update Pool" msgstr "Pool aktualisieren" msgid "Updated At" msgstr "Aktualisiert am" msgid "" "Use the key-manager service to create any certificate containers before " "creating the listener.\n" " The following documentation provides information on how to create a " "certificate container:" msgstr "" "Benutzen Sie den Schlüsselverwaltungsdienst zum Erstellen jeglicher " "Zertifikat-Container, bevor die Listener erstellt werden.\n" " Die folgende Dokumentation stellt Informationen bereit, wie Zertifikat-" "Container zu erstellen sind:" msgid "Value" msgstr "Wert" msgid "Value:" msgstr "Wert:" msgid "Weight" msgstr "Gewicht" msgid "Weight:" msgstr "Gewicht:" msgid "" "When true the logic of the rule is inverted. For example, with invert\n" " true, equal to would become not equal to." msgstr "" "Wenn wahr, ist die Logik der Regel invertiert. Zum Beispiel mit Invertieren\n" " wahr, gleich zu würde nicht gleich sein" msgid "X-Forwarded-For" msgstr "X-Forwarded-For" msgid "X-Forwarded-Port" msgstr "X-Forwarded-Port" msgid "X-Forwarded-Proto" msgstr "X-Forwarded-Proto" msgid "Yes" msgstr "Ja" #, python-format msgid "" "You are about to disassociate the floating IP address from load balancer \"%s" "\". Please confirm." msgstr "" "Sie sind im Begriff, die Verbindung der Floating-IP-Adresse vom Loadbalancer " "%s zu lösen. Bitte bestätigen Sie." #, python-format msgid "You have selected \"%s\". Deleted L7 Policy is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted L7 Policies are not recoverable." msgstr[0] "" "Sie haben \"%s\" gewählt. Eine gelöschte L7 Richtlinie kann nicht " "wiederhergestellt werden." msgstr[1] "" "Sie haben \"%s\" gewählt. Gelöschte L7 Richtlinien können nicht " "wiederhergestellt werden." #, python-format msgid "You have selected \"%s\". Deleted L7 Rule is not recoverable." msgid_plural "You have selected \"%s\". Deleted L7 Rules are not recoverable." msgstr[0] "" "Sie haben \"%s\" ausgewählt. Eine gelöschte L7 Regel kann nicht " "wiederhergestellt werden." msgstr[1] "" "Sie haben \"%s\" ausgewählt. Gelöschte L7 Regeln können nicht " "wiederhergestellt werden." #, python-format msgid "You have selected \"%s\". Deleted health monitor is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted health monitors are not recoverable." msgstr[0] "" "Sie haben \"%s\" ausgewählt. Gelöschter Gesundheitsmonitor kann nicht " "wiederhergestellt werden." msgstr[1] "" "Sie haben \"%s\" ausgewählt. Gelöschter Gesundheitsmonitore können nicht " "wiederhergestellt werden." #, python-format msgid "You have selected \"%s\". Deleted listener is not recoverable." msgid_plural "You have selected \"%s\". Deleted listeners are not recoverable." msgstr[0] "" "Sie haben \"%s\" ausgewählt. Gelöschte Listener können nicht " "wiederhergestellt werden." msgstr[1] "" "Sie haben \"%s\" ausgewählt. Gelöschte Listener können nicht " "wiederhergestellt werden." #, python-format msgid "" "You have selected \"%s\". Deleted load balancer is not recoverable and this " "deletion will delete all of the sub-resources." msgid_plural "" "You have selected \"%s\". Deleted load balancers are not recoverable and " "this deletion will delete all of the sub-resources." msgstr[0] "" "Sie haben \"%s\" ausgewählt. Gelöschte Loadbalancer können nicht " "wiederhergestellt werden und die Aktion löscht auch alle Unterressourcen." msgstr[1] "" "Sie haben \"%s\" ausgewählt. Gelöschte Loadbalancer können nicht " "wiederhergestellt werden und die Aktion löscht auch alle Unterressourcen." #, python-format msgid "You have selected \"%s\". Deleted member is not recoverable." msgid_plural "You have selected \"%s\". Deleted members are not recoverable." msgstr[0] "" "Sie haben \"%s\" ausgewählt. Gelöschte Mitglieder können nicht " "wiederhergestellt werden." msgstr[1] "" "Sie haben \"%s\" ausgewählt. Gelöschte Mitglieder können nicht " "wiederhergestellt werden." #, python-format msgid "You have selected \"%s\". Deleted pool is not recoverable." msgid_plural "You have selected \"%s\". Deleted pools are not recoverable." msgstr[0] "" "Sie haben \"%s\" ausgewählt. Gelöschte Pools können nicht wiederhergestellt " "werden." msgstr[1] "" "Sie haben \"%s\" ausgewählt. Gelöschte Pools können nicht wiederhergestellt " "werden." ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4521008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/en_AU/0000775000175100017510000000000015033037476023075 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/en_AU/LC_MESSAGES/0000775000175100017510000000000015033037476024662 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/en_AU/LC_MESSAGES/django.po0000664000175100017510000000116715033037474026467 0ustar00mylesmyles# Hengqing Hu , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2018-02-27 12:38+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-12-17 01:09+0000\n" "Last-Translator: Copied by Zanata \n" "Language-Team: English (Australia)\n" "Language: en_AU\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "Load Balancers" msgstr "Load Balancers" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.453101 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/en_GB/0000775000175100017510000000000015033037476023060 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/en_GB/LC_MESSAGES/0000775000175100017510000000000015033037476024645 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/en_GB/LC_MESSAGES/django.po0000664000175100017510000000115315033037474026445 0ustar00mylesmyles# Andi Chandler , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2018-02-27 12:38+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-12-14 09:16+0000\n" "Last-Translator: Jacky Hu \n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "Load Balancers" msgstr "Load Balancers" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/en_GB/LC_MESSAGES/djangojs.po0000664000175100017510000012607715033037474027017 0ustar00mylesmyles# Andi Chandler , 2017. #zanata # Jacky Hu , 2017. #zanata # Andi Chandler , 2018. #zanata # Andi Chandler , 2019. #zanata # Andi Chandler , 2020. #zanata # Andi Chandler , 2022. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2022-08-16 20:34+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2022-05-25 09:29+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #, python-format msgid "%(ip)s..." msgstr "%(ip)s..." msgid "A new health monitor is being created." msgstr "A new health monitor is being created." msgid "A new l7 policy is being created." msgstr "A new L7 policy is being created." msgid "A new listener is being created." msgstr "A new listener is being created." msgid "A new load balancer is being created." msgstr "A new load balancer is being created." msgid "A new pool is being created." msgstr "A new pool is being created." msgid "" "A newline separated list of cidrs to be allowed to connect to the listener.\n" " An empty list means allow from any." msgstr "" "A newline separated list of CIDRs to be allowed to connect to the listener.\n" " An empty list means allow from any." msgid "" "A pool represents a group of members over which the load balancing will be " "applied." msgstr "" "A pool represents a group of members over which the load balancing will be " "applied." msgid "" "A string of the allowed ciphers using the OpenSSL syntax. The syntax\n" " is a colon separated list of the chiphers, ex.\n" " \"TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:" "TLS_AES_128_GCM_SHA256\"\n" " Note, don't include quotation marks. An empty string sets the default TLS\n" " Cipher String configured in Octavia." msgstr "" "A string of the allowed ciphers using the OpenSSL syntax. The syntax\n" " is a colon-separated list of the ciphers, ex.\n" " \"TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:" "TLS_AES_128_GCM_SHA256\"\n" " Note, don't include quotation marks. An empty string sets the default TLS\n" " Cipher String configured in Octavia." msgid "APP_COOKIE: Session persistence based on application cookie." msgstr "APP_COOKIE: Session persistence based on application cookie." msgid "Action" msgstr "Action" msgid "Action:" msgstr "Action:" msgid "Active" msgstr "Active" msgid "Add" msgstr "Add" msgid "Add external member" msgstr "Add external member" msgid "Add members to the load balancer pool." msgstr "Add members to the load balancer pool." msgid "Add/Remove Members" msgstr "Add/Remove Members" msgid "Add/Remove Pool Members" msgstr "Add/Remove Pool Members" msgid "" "Additional headers insertion into HTTP header,\n" " only \"X-Forwarded-For\", \"X-Forwarded-Port\" and \"X-Forwarded-Proto\" " "are supported." msgstr "" "Additional headers insertion into HTTP header,\n" " only \"X-Forwarded-For\", \"X-Forwarded-Port\" and \"X-Forwarded-Proto\" " "are supported." msgid "Admin State Up" msgstr "Admin State Up" msgid "Algorithm" msgstr "Algorithm" msgid "Algorithm:" msgstr "Algorithm:" msgid "Allocated Members" msgstr "Allocated Members" msgid "Allowed Cidrs" msgstr "Allowed CIDRs" msgid "Allowed Cidrs:" msgstr "Allowed CIDRs:" msgid "" "An L7 Policy is a collection of L7 rules associated with a Listener, and " "which may also have an association to a back-end pool" msgstr "" "An L7 Policy is a collection of L7 rules associated with a Listener, and " "which may also have an association to a back-end pool" msgid "" "An L7 Rule is a single, simple logical test which returns either true or\n" "false." msgstr "" "An L7 Rule is a single, simple logical test which returns either true or\n" "false." msgid "" "An alternate IP address used for health monitoring a backend member.\n" " Default is null which monitors the member address." msgstr "" "An alternate IP address used for health monitoring a backend member.\n" " Default is null which monitors the member address." msgid "" "An alternate protocol port used for health monitoring a backend member.\n" " Default is null which monitors the member protocol port." msgstr "" "An alternate protocol port used for health monitoring a backend member.\n" " Default is null which monitors the member protocol port." msgid "An error occurred. Please try again later." msgstr "An error occurred. Please try again later." msgid "Associate" msgstr "Associate" msgid "Associate Floating IP" msgstr "Associate Floating IP" msgid "Associate Floating IP Address" msgstr "Associate Floating IP Address" msgid "Associating floating IP with load balancer." msgstr "Associating floating IP with load balancer." msgid "Availability Zone" msgstr "Availability Zone" msgid "Available Instances" msgstr "Available Instances" msgid "Backend member connection timeout in milliseconds. Default: 5000." msgstr "Backend member connection timeout in milliseconds. Default: 5000." msgid "Backend member inactivity timeout in milliseconds. Default: 50000." msgstr "Backend member inactivity timeout in milliseconds. Default: 50000." msgid "Backup" msgstr "Backup" msgid "Backup:" msgstr "Backup:" msgid "CIDR" msgstr "CIDR" msgid "CONTAINS: String contains." msgstr "CONTAINS: String contains." msgid "" "COOKIE: The rule looks for a cookie named by the key parameter and\n" " compares it against the value parameter in the rule." msgstr "" "COOKIE: The rule looks for a cookie named by the key parameter and\n" " compares it against the value parameter in the rule." msgid "Cancel" msgstr "Cancel" msgid "Certificate Name" msgstr "Certificate Name" msgid "Client Data Timeout" msgstr "Client Data Timeout" msgid "Client Data Timeout:" msgstr "Client Data Timeout:" msgid "Compare Type" msgstr "Compare Type" msgid "Compare Type:" msgstr "Compare Type:" msgid "Confirm Delete Health Monitor" msgid_plural "Confirm Delete Health Monitors" msgstr[0] "Confirm Delete Health Monitor" msgstr[1] "Confirm Delete Health Monitors" msgid "Confirm Delete L7 Policy" msgid_plural "Confirm Delete L7 Policies" msgstr[0] "Confirm Delete L7 Policy" msgstr[1] "Confirm Delete L7 Policies" msgid "Confirm Delete L7 Rule" msgid_plural "Confirm Delete L7 Rules" msgstr[0] "Confirm Delete L7 Rule" msgstr[1] "Confirm Delete L7 Rules" msgid "Confirm Delete Listener" msgid_plural "Confirm Delete Listeners" msgstr[0] "Confirm Delete Listener" msgstr[1] "Confirm Delete Listeners" msgid "Confirm Delete Load Balancer" msgid_plural "Confirm Delete Load Balancers" msgstr[0] "Confirm Delete Load Balancer" msgstr[1] "Confirm Delete Load Balancers" msgid "Confirm Delete Member" msgid_plural "Confirm Delete Members" msgstr[0] "Confirm Delete Member" msgstr[1] "Confirm Delete Members" msgid "Confirm Delete Pool" msgid_plural "Confirm Delete Pools" msgstr[0] "Confirm Delete Pool" msgstr[1] "Confirm Delete Pools" msgid "Confirm Disassociate Floating IP Address" msgstr "Confirm Disassociate Floating IP Address" msgid "Connection Limit" msgstr "Connection Limit" msgid "Connection Limit:" msgstr "Connection Limit:" msgid "Contains" msgstr "Contains" msgid "Cookie" msgstr "Cookie" msgid "Cookie Name" msgstr "Cookie Name" msgid "Create Health Monitor" msgstr "Create Health Monitor" msgid "Create L7 Policy" msgstr "Create L7 Policy" msgid "Create L7 Rule" msgstr "Create L7 Rule" msgid "Create Listener" msgstr "Create Listener" msgid "Create Load Balancer" msgstr "Create Load Balancer" msgid "Create Pool" msgstr "Create Pool" msgid "Created At" msgstr "Created At" msgid "Default Pool ID" msgstr "Default Pool ID" msgid "Default Pool ID:" msgstr "Default Pool ID:" msgid "Default TLS Container Ref" msgstr "Default TLS Container Ref" msgid "Degraded" msgstr "Degraded" msgid "Delay" msgstr "Delay" msgid "Delay (sec)" msgstr "Delay (sec)" msgid "Delay:" msgstr "Delay:" msgid "Delete Health Monitor" msgid_plural "Delete Health Monitors" msgstr[0] "Delete Health Monitor" msgstr[1] "Delete Health Monitors" msgid "Delete Health Monitors" msgstr "Delete Health Monitors" msgid "Delete L7 Policies" msgstr "Delete L7 Policies" msgid "Delete L7 Policy" msgid_plural "Delete L7 Policies" msgstr[0] "Delete L7 Policy" msgstr[1] "Delete L7 Policies" msgid "Delete L7 Rule" msgid_plural "Delete L7 Rules" msgstr[0] "Delete L7 Rule" msgstr[1] "Delete L7 Rules" msgid "Delete L7 Rules" msgstr "Delete L7 Rules" msgid "Delete Listener" msgid_plural "Delete Listeners" msgstr[0] "Delete Listener" msgstr[1] "Delete Listeners" msgid "Delete Listeners" msgstr "Delete Listeners" msgid "Delete Load Balancer" msgid_plural "Delete Load Balancers" msgstr[0] "Delete Load Balancer" msgstr[1] "Delete Load Balancers" msgid "Delete Load Balancers" msgstr "Delete Load Balancers" msgid "Delete Member" msgid_plural "Delete Members" msgstr[0] "Delete Member" msgstr[1] "Delete Members" msgid "Delete Members" msgstr "Delete Members" msgid "Delete Pool" msgid_plural "Delete Pools" msgstr[0] "Delete Pool" msgstr[1] "Delete Pools" msgid "Delete Pools" msgstr "Delete Pools" #, python-format msgid "Deleted Health Monitor: %s." msgid_plural "Deleted Health Monitors: %s." msgstr[0] "Deleted Health Monitor: %s." msgstr[1] "Deleted Health Monitors: %s." #, python-format msgid "Deleted L7 Policy: %s." msgid_plural "Deleted L7 Policies: %s." msgstr[0] "Deleted L7 Policy: %s." msgstr[1] "Deleted L7 Policies: %s." #, python-format msgid "Deleted L7 Rule: %s." msgid_plural "Deleted L7 Rules: %s." msgstr[0] "Deleted L7 Rule: %s." msgstr[1] "Deleted L7 Rules: %s." #, python-format msgid "Deleted Listener: %s." msgid_plural "Deleted Listeners: %s." msgstr[0] "Deleted Listener: %s." msgstr[1] "Deleted Listeners: %s." #, python-format msgid "Deleted Load Balancer: %s." msgid_plural "Deleted Load Balancers: %s." msgstr[0] "Deleted Load Balancer: %s." msgstr[1] "Deleted Load Balancers: %s." #, python-format msgid "Deleted Member: %s." msgid_plural "Deleted Members: %s." msgstr[0] "Deleted Member: %s." msgstr[1] "Deleted Members: %s." #, python-format msgid "Deleted Pool: %s." msgid_plural "Deleted Pools: %s." msgstr[0] "Deleted Pool: %s." msgstr[1] "Deleted Pools: %s." msgid "Description" msgstr "Description" msgid "Disassociate" msgstr "Disassociate" msgid "Disassociate Floating IP" msgstr "Disassociate Floating IP" #, python-format msgid "Disassociated floating IP address from load balancer: %s." msgstr "Disassociated floating IP address from load balancer: %s." msgid "Draining" msgstr "Draining" msgid "ENDS_WITH: String ends with." msgstr "ENDS_WITH: String ends with." msgid "EQUAL_TO: String is equal to." msgstr "EQUAL_TO: String is equal to." msgid "" "Each port that listens for traffic on a particular load balancer is " "configured separately and\n" " tied to the load balancer. Multiple listeners can be associated with the " "same load balancer but\n" " each must use a unique port." msgstr "" "Each port that listens for traffic on a particular load balancer is " "configured separately and\n" " tied to the load balancer. Multiple listeners can be associated with the " "same load balancer but\n" " each must use a unique port." msgid "Edit Health Monitor" msgstr "Edit Health Monitor" msgid "Edit L7 Policy" msgstr "Edit L7 Policy" msgid "Edit L7 Rule" msgstr "Edit L7 Rule" msgid "Edit Listener" msgstr "Edit Listener" msgid "Edit Load Balancer" msgstr "Edit Load Balancer" msgid "Edit Member" msgstr "Edit Member" msgid "Edit Pool" msgstr "Edit Pool" msgid "" "Enable TLS for backend re-encryption, communications between the load\n" " balancer and the member servers are encrypted." msgstr "" "Enable TLS for backend re-encryption, communications between the load\n" " balancer and the member servers are encrypted." msgid "Ends With" msgstr "Ends With" msgid "Equal To" msgstr "Equal To" msgid "Error" msgstr "Error" msgid "Expected Codes" msgstr "Expected Codes" msgid "Expected Codes:" msgstr "Expected Codes:" msgid "Expiration Date" msgstr "Expiration Date" msgid "" "FILE_TYPE: The rule compares the last portion of the URI against\n" " the value parameter in the rule. (eg. \"txt\", \"jpg\", etc.)" msgstr "" "FILE_TYPE: The rule compares the last portion of the URI against\n" " the value parameter in the rule. (eg. \"txt\", \"jpg\", etc.)" msgid "File Type" msgstr "File Type" msgid "Flavor" msgstr "Flavour" msgid "Flavor Description" msgstr "Flavour Description" msgid "Flavor ID" msgstr "Flavour ID" msgid "Floating IP" msgstr "Floating IP" msgid "Floating IP address or pool" msgstr "Floating IP address or pool" msgid "Floating IP addresses" msgstr "Floating IP addresses" msgid "Floating IP pools" msgstr "Floating IP pools" msgid "Frontend client inactivity timeout in milliseconds. Default: 50000." msgstr "Frontend client inactivity timeout in milliseconds. Default: 50000." msgid "" "HEADER: The rule looks for a header defined in the key parameter\n" " and compares it against the value parameter in the rule." msgstr "" "HEADER: The rule looks for a header defined in the key parameter\n" " and compares it against the value parameter in the rule." msgid "" "HOST_NAME: The rule does a comparison between the HTTP/1.1\n" " hostname in the request against the value parameter in the rule." msgstr "" "HOST_NAME: The rule does a comparison between the HTTP/1.1\n" " hostname in the request against the value parameter in the rule." msgid "HTTP Method" msgstr "HTTP Method" msgid "HTTP Method:" msgstr "HTTP Method:" msgid "HTTP_COOKIE: Session persistence based on http cookie." msgstr "HTTP_COOKIE: Session persistence based on HTTP cookie." msgid "Header" msgstr "Header" msgid "Health Monitor" msgstr "Health Monitor" msgid "Health Monitor ID" msgstr "Health Monitor ID" msgid "Health Monitors" msgstr "Health Monitors" msgid "Host Name" msgstr "Host Name" msgid "ID" msgstr "ID" msgid "IP Address" msgstr "IP Address" #, python-format msgid "IP Addresses (%(count)s)" msgstr "IP Addresses (%(count)s)" msgid "IP address" msgstr "IP address" msgid "IP address:" msgstr "IP address:" msgid "" "If an IP address is provided it must be a well-formed IPv4 or IPv6 address. " "The system will\n" " attempt to assign the provided IP address to the load balancer. If an IP " "address is not provided\n" " then one will be allocated for you." msgstr "" "If an IP address is provided it must be a well-formed IPv4 or IPv6 address. " "The system will\n" " attempt to assign the provided IP address to the load balancer. If an IP " "address is not provided\n" " then one will be allocated for you." msgid "" "If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL " "certificates must\n" " be selected. The first certificate will be the default." msgstr "" "If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL " "certificates must\n" " be selected. The first certificate will be the default." msgid "Inactive" msgstr "Inactive" msgid "Insert Headers" msgstr "Insert Headers" msgid "Insert Headers:" msgstr "Insert Headers:" msgid "Invert" msgstr "Invert" msgid "Invert:" msgstr "Invert:" msgid "" "Is the member a backup? Backup members only receive traffic when all\n" " non-backup members are down." msgstr "" "Is the member a backup? Backup members only receive traffic when all\n" " non-backup members are down." msgid "Key" msgstr "Key" msgid "Key Manager API Guide: Creating a Certificate Container" msgstr "Key Manager API Guide: Creating a Certificate Container" msgid "Key Manager Service Command-Line Client" msgstr "Key Manager Service Command-Line Client" msgid "Key:" msgstr "Key:" msgid "L7 Policies" msgstr "L7 Policies" msgid "L7 Policy" msgstr "L7 Policy" msgid "L7 Policy Details" msgstr "L7 Policy Details" msgid "L7 Rule" msgstr "L7 Rule" msgid "L7 Rule Details" msgstr "L7 Rule Details" msgid "L7 Rules" msgstr "L7 Rules" msgid "" "LEAST_CONNECTIONS: Allocates requests to the instance with the least number " "of active\n" " connections." msgstr "" "LEAST_CONNECTIONS: Allocates requests to the instance with the least number " "of active\n" " connections." msgid "Least Connections" msgstr "Least Connections" msgid "Listener" msgstr "Listener" msgid "Listener Details" msgstr "Listener Details" msgid "Listener ID" msgstr "Listener ID" msgid "Listeners" msgstr "Listeners" msgid "Load Balancer" msgstr "Load Balancer" msgid "Load Balancer Details" msgstr "Load Balancer Details" msgid "Load Balancers" msgstr "Load Balancers" msgid "Loading" msgstr "Loading" msgid "Max Retries" msgstr "Max Retries" msgid "Max Retries Down" msgstr "Max Retries Down" msgid "Max Retries Down:" msgstr "Max Retries Down:" msgid "Max Retries:" msgstr "Max Retries:" msgid "Member" msgstr "Member" msgid "Member Connect Timeout" msgstr "Member Connect Timeout" msgid "Member Connect Timeout:" msgstr "Member Connect Timeout:" msgid "Member Data Timeout" msgstr "Member Data Timeout" msgid "Member Data Timeout:" msgstr "Member Data Timeout:" msgid "Members" msgstr "Members" msgid "" "Members are the actual IP addresses that will receive traffic from the load " "balancer. Each\n" " member must have a unique combination of IP address and port." msgstr "" "Members are the actual IP addresses that will receive traffic from the load " "balancer. Each\n" " member must have a unique combination of IP address and port." msgid "Monitor Address" msgstr "Monitor Address" msgid "Monitor Address:" msgstr "Monitor Address:" msgid "Monitor Details" msgstr "Monitor Details" msgid "Monitor Port" msgstr "Monitor Port" msgid "Monitor Port:" msgstr "Monitor Port:" msgid "Name" msgstr "Name" msgid "Network" msgstr "Network" msgid "Network ID" msgstr "Network ID" msgid "No" msgstr "No" msgid "No Monitor" msgstr "No Monitor" msgid "No available certificates" msgstr "No available certificates" msgid "No available instances" msgstr "No available instances" msgid "No items to display." msgstr "No items to display." msgid "No matching options" msgstr "No matching options" msgid "No members have been allocated" msgstr "No members have been allocated" msgid "None" msgstr "None" msgid "Offline" msgstr "Offline" msgid "Online" msgstr "Online" msgid "Operating Status" msgstr "Operating Status" msgid "Overview" msgstr "Overview" msgid "" "PATH: The rule compares the path portion of the HTTP URI against\n" " the value parameter in the rule." msgstr "" "PATH: The rule compares the path portion of the HTTP URI against\n" " the value parameter in the rule." msgid "Path" msgstr "Path" msgid "Pending Create" msgstr "Pending Create" msgid "Pending Delete" msgstr "Pending Delete" msgid "Pending Update" msgstr "Pending Update" msgid "Please Wait" msgstr "Please Wait" msgid "Pool" msgstr "Pool" msgid "Pool Details" msgstr "Pool Details" msgid "Pool Members" msgstr "Pool Members" msgid "Pool member has been updated." msgstr "Pool member has been updated." msgid "Pools" msgstr "Pools" msgid "Port" msgstr "Port" msgid "Port ID" msgstr "Port ID" msgid "Port:" msgstr "Port:" msgid "Position" msgstr "Position" msgid "Position:" msgstr "Position:" msgid "Project" msgstr "Project" msgid "Project ID" msgstr "Project ID" msgid "Protocol" msgstr "Protocol" msgid "Protocol Port" msgstr "Protocol Port" msgid "Protocol:" msgstr "Protocol:" msgid "Provide the details for the health monitor." msgstr "Provide the details for the health monitor." msgid "Provide the details for the l7 policy." msgstr "Provide the details for the L7 policy." msgid "Provide the details for the l7 rule." msgstr "Provide the details for the L7 rule." msgid "Provide the details for the listener." msgstr "Provide the details for the listener." msgid "Provide the details for the load balancer." msgstr "Provide the details for the load balancer." msgid "Provide the details for the member." msgstr "Provide the details for the member." msgid "Provide the details for the pool." msgstr "Provide the details for the pool." msgid "Provider" msgstr "Provider" msgid "Provisioning Status" msgstr "Provisioning Status" msgid "" "REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated " "with the L7 policy." msgstr "" "REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated " "with the L7 policy." msgid "" "REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in " "the redirect_url parameter." msgstr "" "REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in " "the redirect_url parameter." msgid "REGEX: Perl type regular expression matching." msgstr "REGEX: Perl type regular expression matching." msgid "" "REJECT: The request is denied with an appropriate response code, and not " "forwarded on to any back-end pool." msgstr "" "REJECT: The request is denied with an appropriate response code, and not " "forwarded on to any back-end pool." msgid "ROUND_ROBIN: Rotates requests evenly between multiple instances." msgstr "ROUND_ROBIN: Rotates requests evenly between multiple instances." msgid "Redirect Pool ID" msgstr "Redirect Pool ID" msgid "Redirect Pool ID:" msgstr "Redirect Pool ID:" msgid "Redirect URL" msgstr "Redirect URL" msgid "Redirect URL:" msgstr "Redirect URL:" msgid "Redirect to Pool" msgstr "Redirect to Pool" msgid "Redirect to URL" msgstr "Redirect to URL" msgid "Regex" msgstr "Regex" msgid "Reject" msgstr "Reject" msgid "Remove" msgstr "Remove" msgid "" "Requests matching this policy will be redirected to the pool with this ID. " "Only valid if action is REDIRECT_TO_POOL." msgstr "" "Requests matching this policy will be redirected to the pool with this ID. " "Only valid if action is REDIRECT_TO_POOL." msgid "" "Requests matching this policy will be redirected to this URL. Only valid if " "action is REDIRECT_TO_URL." msgstr "" "Requests matching this policy will be redirected to this URL. Only valid if " "action is REDIRECT_TO_URL." msgid "Round Robin" msgstr "Round Robin" msgid "Rules" msgstr "Rules" msgid "SNI Container Refs" msgstr "SNI Container Refs" msgid "" "SOURCE_IP: Requests from a unique source IP address are consistently " "directed to the same instance." msgstr "" "SOURCE_IP: Requests from a unique source IP address are consistently " "directed to the same instance." msgid "SOURCE_IP: Session persistence based on source ip." msgstr "SOURCE_IP: Session persistence based on source IP." msgid "SSL Certificates" msgstr "SSL Certificates" msgid "STARTS_WITH: String starts with." msgstr "STARTS_WITH: String starts with." msgid "" "Select a floating IP address to associate with the load balancer or a " "floating IP pool in which to allocate a new floating IP address." msgstr "" "Select a floating IP address to associate with the load balancer or a " "floating IP pool in which to allocate a new floating IP address." msgid "Select certificates from the available certificates below" msgstr "Select certificates from the available certificates below" msgid "Select one or more SSL certificates for the listener." msgstr "Select one or more SSL certificates for the listener." msgid "Session Persistence" msgstr "Session Persistence" msgid "Session Persistence:" msgstr "Session Persistence:" msgid "Source IP" msgstr "Source IP" msgid "Starts With" msgstr "Starts With" msgid "Subnet" msgstr "Subnet" msgid "Subnet ID" msgstr "Subnet ID" msgid "Subnet:" msgstr "Subnet:" msgid "TCP Inspect Timeout" msgstr "TCP Inspect Timeout" msgid "TCP Inspect Timeout:" msgstr "TCP Inspect Timeout:" msgid "TLS Cipher String" msgstr "TLS Cipher String" msgid "TLS Cipher String:" msgstr "TLS Cipher String:" msgid "TLS Enabled" msgstr "TLS Enabled" msgid "TLS Enabled:" msgstr "TLS Enabled:" msgid "" "The Available Instances table contains existing compute instances that can " "be added as members\n" " of the pool. Use the \"Add external member\" button to add a member not " "found in the Available\n" " Instances table." msgstr "" "The Available Instances table contains existing compute instances that can " "be added as members\n" " of the pool. Use the \"Add external member\" button to add a member not " "found in the Available\n" " Instances table." msgid "The HTTP method used to perform the health check." msgstr "The HTTP method used to perform the health check." msgid "The ID of the pool used by the listener if no L7 policies match." msgstr "The ID of the pool used by the listener if no L7 policies match." msgid "The IP address is not valid." msgstr "The IP address is not valid." msgid "" "The IP address of the member to receive traffic from the load balancer. Must " "be a well-formed\n" " IPv4 or IPv6 address." msgstr "" "The IP address of the member to receive traffic from the load balancer. Must " "be a well-formed\n" " IPv4 or IPv6 address." msgid "" "The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL." msgstr "" "The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL." msgid "The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH." msgstr "" "The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH." msgid "The URL path is not valid." msgstr "The URL path is not valid." msgid "The cipher string must conform to OpenSSL syntax." msgstr "The cipher string must conform to OpenSSL syntax." msgid "" "The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, or STARTS_WITH." msgstr "" "The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, or STARTS_WITH." msgid "The connection limit must be a number greater than or equal to -1." msgstr "The connection limit must be a number greater than or equal to -1." msgid "" "The expected HTTP status codes to get from a successful health check. Must " "be a single number,\n" " a comma separated list of numbers, or a range (two numbers separated by a " "hyphen)." msgstr "" "The expected HTTP status codes to get from a successful health check. Must " "be a single number,\n" " a comma separated list of numbers, or a range (two numbers separated by a " "hyphen)." msgid "The expected status code is not valid." msgstr "The expected status code is not valid." msgid "The health check interval must be greater than or equal to the timeout." msgstr "" "The health check interval must be greater than or equal to the timeout." msgid "The health monitor has been updated." msgstr "The health monitor has been updated." msgid "" "The health monitor is used to determine the health of your pool members. " "Health checks\n" " routinely run against each member within the pool and the result of the " "health check is used\n" " to determine if the member receives new connections. Each pool can only " "have one health\n" " monitor." msgstr "" "The health monitor is used to determine the health of your pool members. " "Health checks\n" " routinely run against each member within the pool and the result of the " "health check is used\n" " to determine if the member receives new connections. Each pool can only " "have one health\n" " monitor." msgid "" "The interval between health checks. Must be greater than or equal to the " "timeout." msgstr "" "The interval between health checks. Must be greater than or equal to the " "timeout." msgid "" "The key to use for the comparison. For example, the name of the cookie\n" " to evaluate." msgstr "" "The key to use for the comparison. For example, the name of the cookie\n" " to evaluate." msgid "The l7policy has been updated." msgstr "The L7policy has been updated." msgid "The l7rule has been updated." msgstr "The L7rule has been updated." msgid "The listener has been updated." msgstr "The listener has been updated." msgid "" "The load balancer algorithm that distributes traffic to the pool members." msgstr "" "The load balancer algorithm that distributes traffic to the pool members." msgid "The load balancer has been updated." msgstr "The load balancer has been updated." msgid "" "The load balancer occupies a neutron network port and has an IP address " "assigned from a subnet." msgstr "" "The load balancer occupies a neutron network port and has an IP address " "assigned from a subnet." msgid "The max retry count must be a number between 1 and 10." msgstr "The max retry count must be a number between 1 and 10." msgid "The max retry down count must be a number between 1 and 10." msgstr "The max retry down count must be a number between 1 and 10." msgid "" "The maximum number of connections permitted for this listener.\n" " Default value is -1 which represents infinite connections." msgstr "" "The maximum number of connections permitted for this listener.\n" " Default value is -1 which represents infinite connections." msgid "The monitor address must be a valid IP address." msgstr "The monitor address must be a valid IP address." msgid "The monitor port must be a number between 1 and 65535." msgstr "The monitor port must be a number between 1 and 65535." msgid "The network on which to allocate the load balancer's IP address." msgstr "The network on which to allocate the load balancer's IP address." msgid "The network which contains the IP address of the member." msgstr "The network which contains the IP address of the member." msgid "" "The number of allowed connection failures before marking the member as " "error. Must be a\n" " number from 1 to 10. The default is 3." msgstr "" "The number of allowed connection failures before marking the member as " "error. Must be a\n" " number from 1 to 10. The default is 3." msgid "" "The number of allowed connection failures before marking the member as " "inactive. Must be a\n" " number from 1 to 10." msgstr "" "The number of allowed connection failures before marking the member as " "inactive. Must be a\n" " number from 1 to 10." msgid "The pool has been updated." msgstr "The pool has been updated." msgid "The pool members have been updated." msgstr "The pool members have been updated." msgid "The port must be a number between 1 and 65535." msgstr "The port must be a number between 1 and 65535." msgid "" "The port must be unique among all listeners attached to this load balancer." msgstr "" "The port must be unique among all listeners attached to this load balancer." msgid "" "The port on which the front end listens. Must be an integer from 1 to 65535." msgstr "" "The port on which the front end listens. Must be an integer from 1 to 65535." msgid "" "The port on which the member listens for traffic. Must be a number from 1 to " "65535." msgstr "" "The port on which the member listens for traffic. Must be a number from 1 to " "65535." msgid "The position must be a number between 1 and 2147483647." msgstr "The position must be a number between 1 and 2147483647." msgid "The position of this policy on the listener. Positions start at 1." msgstr "The position of this policy on the listener. Positions start at 1." msgid "" "The protocol for which the front end listens. The TERMINATED_HTTPS protocol " "is only available if\n" " the key-manager service is enabled and you have authority to list " "certificate containers and\n" " secrets." msgstr "" "The protocol for which the front end listens. The TERMINATED_HTTPS protocol " "is only available if\n" " the key-manager service is enabled and you have authority to list " "certificate containers and\n" " secrets." msgid "" "The protocol for which this pool and its members listen. A valid value is " "HTTP, HTTPS, PROXY, PROXYV2, TCP, UDP or SCTP." msgstr "" "The protocol for which this pool and its members listen. A valid value is " "HTTP, HTTPS, PROXY, PROXYV2, TCP, UDP or SCTP." msgid "The redirect url must be a valid http or https url." msgstr "The redirect URL must be a valid HTTP or HTTPS URL." msgid "" "The target of the health check HTTP request to the member. Must be a valid " "URL path." msgstr "" "The target of the health check HTTP request to the member. Must be a valid " "URL path." msgid "" "The time after which a health check times out. Must be a number greater than " "or equal to 0\n" " and less than or equal to the interval." msgstr "" "The time after which a health check times out. Must be a number greater than " "or equal to 0\n" " and less than or equal to the interval." msgid "The timeout must be a number between 0 and 31536000000." msgstr "The timeout must be a number between 0 and 31536000000." msgid "The timeout must be a number greater than or equal to 0." msgstr "The timeout must be a number greater than or equal to 0." msgid "" "The type of session persistence for distributing traffic to the pool members." msgstr "" "The type of session persistence for distributing traffic to the pool members." msgid "" "The value to use for the comparison. For example, the file type to compare." msgstr "" "The value to use for the comparison. For example, the file type to compare." msgid "The weight must be a number between 0 and 256." msgstr "The weight must be a number between 0 and 256." msgid "" "The weight of a member determines the portion of requests or connections it " "services compared\n" " to the other members of the pool. A value of 0 means the member does not " "receive new connections\n" " but continues to service existing connections. A higher weight means it " "will receive more\n" " traffic. Must be a number from 0 to 256." msgstr "" "The weight of a member determines the portion of requests or connections it " "services compared\n" " to the other members of the pool. A value of 0 means the member does not " "receive new connections\n" " but continues to service existing connections. A higher weight means it " "will receive more\n" " traffic. Must be a number from 0 to 256." msgid "" "Time, in milliseconds, to wait for additional TCP packets for content\n" " inspection. Default: 0." msgstr "" "Time, in milliseconds, to wait for additional TCP packets for content\n" " inspection. Default: 0." msgid "Timeout" msgstr "Timeout" msgid "Timeout (sec)" msgstr "Timeout (sec)" msgid "Timeout:" msgstr "Timeout:" msgid "Type" msgstr "Type" msgid "Type:" msgstr "Type:" msgid "URL Path" msgstr "URL Path" msgid "URL Path:" msgstr "URL Path:" msgid "Unable to create flavor profile." msgstr "Unable to create flavour profile." msgid "Unable to create flavor." msgstr "Unable to create flavour." msgid "Unable to create health monitor." msgstr "Unable to create health monitor." msgid "Unable to create l7 policy." msgstr "Unable to create L7 policy." msgid "Unable to create l7 rule." msgstr "Unable to create L7 rule." msgid "Unable to create listener." msgstr "Unable to create listener." msgid "Unable to create load balancer." msgstr "Unable to create load balancer." msgid "Unable to create pool." msgstr "Unable to create pool." #, python-format msgid "Unable to delete Health Monitor: %s." msgid_plural "Unable to delete Health Monitors: %s." msgstr[0] "Unable to delete Health Monitor: %s." msgstr[1] "Unable to delete Health Monitors: %s." #, python-format msgid "Unable to delete L7 Policy: %s." msgid_plural "Unable to delete L7 Policies: %s." msgstr[0] "Unable to delete L7 Policy: %s." msgstr[1] "Unable to delete L7 Policies: %s." #, python-format msgid "Unable to delete L7 Rule: %s." msgid_plural "Unable to delete L7 Rules: %s." msgstr[0] "Unable to delete L7 Rule: %s." msgstr[1] "Unable to delete L7 Rules: %s." #, python-format msgid "Unable to delete Listener: %s." msgid_plural "Unable to delete Listeners: %s." msgstr[0] "Unable to delete Listener: %s." msgstr[1] "Unable to delete Listeners: %s." #, python-format msgid "Unable to delete Load Balancer: %s." msgid_plural "Unable to delete Load Balancers: %s." msgstr[0] "Unable to delete Load Balancer: %s." msgstr[1] "Unable to delete Load Balancers: %s." #, python-format msgid "Unable to delete Member: %s." msgid_plural "Unable to delete Members: %s." msgstr[0] "Unable to delete Member: %s." msgstr[1] "Unable to delete Members: %s." #, python-format msgid "Unable to delete Pool: %s." msgid_plural "Unable to delete Pools: %s." msgstr[0] "Unable to delete Pool: %s." msgstr[1] "Unable to delete Pools: %s." msgid "Unable to delete flavor profile." msgstr "Unable to delete flavour profile." msgid "Unable to delete flavor." msgstr "Unable to delete flavour." msgid "Unable to delete health monitor." msgstr "Unable to delete health monitor." msgid "Unable to delete l7 policy." msgstr "Unable to delete L7 policy." msgid "Unable to delete l7 rule." msgstr "Unable to delete L7 rule." msgid "Unable to delete listener." msgstr "Unable to delete listener." msgid "Unable to delete load balancer." msgstr "Unable to delete load balancer." msgid "Unable to delete member." msgstr "Unable to delete member." msgid "Unable to delete pool." msgstr "Unable to delete pool." #, python-format msgid "Unable to disassociate floating IP address from load balancer: %s." msgstr "Unable to disassociate floating IP address from load balancer: %s." msgid "Unable to retrieve SSL certificates." msgstr "Unable to retrieve SSL certificates." msgid "Unable to retrieve availability zones." msgstr "Unable to retrieve availability zones." msgid "Unable to retrieve flavor profile." msgstr "Unable to retrieve flavour profile." msgid "Unable to retrieve flavor profiles." msgstr "Unable to retrieve flavour profiles." msgid "Unable to retrieve flavor." msgstr "Unable to retrieve flavour." msgid "Unable to retrieve flavors." msgstr "Unable to retrieve flavours." msgid "Unable to retrieve health monitor." msgstr "Unable to retrieve health monitor." msgid "Unable to retrieve health monitors." msgstr "Unable to retrieve health monitors." msgid "Unable to retrieve l7 policies." msgstr "Unable to retrieve L7 policies." msgid "Unable to retrieve l7 policy." msgstr "Unable to retrieve L7 policy." msgid "Unable to retrieve l7 rule." msgstr "Unable to retrieve L7 rule." msgid "Unable to retrieve l7 rules." msgstr "Unable to retrieve L7 rules." msgid "Unable to retrieve listener." msgstr "Unable to retrieve listener." msgid "Unable to retrieve listeners." msgstr "Unable to retrieve listeners." msgid "Unable to retrieve load balancer." msgstr "Unable to retrieve load balancer." msgid "Unable to retrieve load balancers." msgstr "Unable to retrieve load balancers." msgid "Unable to retrieve member." msgstr "Unable to retrieve member." msgid "Unable to retrieve members." msgstr "Unable to retrieve members." msgid "Unable to retrieve pool." msgstr "Unable to retrieve pool." msgid "Unable to retrieve pools." msgstr "Unable to retrieve pools." msgid "Unable to retrieve secrets." msgstr "Unable to retrieve secrets." msgid "Unable to update flavor profile." msgstr "Unable to update flavour profile." msgid "Unable to update flavor." msgstr "Unable to update flavour." msgid "Unable to update health monitor." msgstr "Unable to update health monitor." msgid "Unable to update l7 policy." msgstr "Unable to update L7 policy." msgid "Unable to update l7 rule." msgstr "Unable to update L7 rule." msgid "Unable to update listener." msgstr "Unable to update listener." msgid "Unable to update load balancer." msgstr "Unable to update load balancer." msgid "Unable to update member list." msgstr "Unable to update member list." msgid "Unable to update member." msgstr "Unable to update member." msgid "Unable to update pool." msgstr "Unable to update pool." msgid "Update" msgstr "Update" msgid "Update Health Monitor" msgstr "Update Health Monitor" msgid "Update L7 Policy" msgstr "Update L7 Policy" msgid "Update L7 Rule" msgstr "Update L7 Rule" msgid "Update Listener" msgstr "Update Listener" msgid "Update Load Balancer" msgstr "Update Load Balancer" msgid "Update Member" msgstr "Update Member" msgid "Update Pool" msgstr "Update Pool" msgid "Updated At" msgstr "Updated At" msgid "" "Use the key-manager service to create any certificate containers before " "creating the listener.\n" " The following documentation provides information on how to create a " "certificate container:" msgstr "" "Use the key-manager service to create any certificate containers before " "creating the listener.\n" " The following documentation provides information on how to create a " "certificate container:" msgid "Value" msgstr "Value" msgid "Value:" msgstr "Value:" msgid "Weight" msgstr "Weight" msgid "Weight:" msgstr "Weight:" msgid "" "When true the logic of the rule is inverted. For example, with invert\n" " true, equal to would become not equal to." msgstr "" "When true the logic of the rule is inverted. For example, with invert\n" " true, equal to would become not equal to." msgid "X-Forwarded-For" msgstr "X-Forwarded-For" msgid "X-Forwarded-Port" msgstr "X-Forwarded-Port" msgid "X-Forwarded-Proto" msgstr "X-Forwarded-Proto" msgid "Yes" msgstr "Yes" #, python-format msgid "" "You are about to disassociate the floating IP address from load balancer \"%s" "\". Please confirm." msgstr "" "You are about to disassociate the floating IP address from load balancer \"%s" "\". Please confirm." #, python-format msgid "You have selected \"%s\". Deleted L7 Policy is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted L7 Policies are not recoverable." msgstr[0] "You have selected \"%s\". Deleted L7 Policy is not recoverable." msgstr[1] "You have selected \"%s\". Deleted L7 Policies are not recoverable." #, python-format msgid "You have selected \"%s\". Deleted L7 Rule is not recoverable." msgid_plural "You have selected \"%s\". Deleted L7 Rules are not recoverable." msgstr[0] "You have selected \"%s\". Deleted L7 Rule is not recoverable." msgstr[1] "You have selected \"%s\". Deleted L7 Rules are not recoverable." #, python-format msgid "You have selected \"%s\". Deleted health monitor is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted health monitors are not recoverable." msgstr[0] "" "You have selected \"%s\". Deleted health monitor is not recoverable." msgstr[1] "" "You have selected \"%s\". Deleted health monitors are not recoverable." #, python-format msgid "You have selected \"%s\". Deleted listener is not recoverable." msgid_plural "You have selected \"%s\". Deleted listeners are not recoverable." msgstr[0] "You have selected \"%s\". Deleted listener is not recoverable." msgstr[1] "You have selected \"%s\". Deleted listeners are not recoverable." #, python-format msgid "" "You have selected \"%s\". Deleted load balancer is not recoverable and this " "deletion will delete all of the sub-resources." msgid_plural "" "You have selected \"%s\". Deleted load balancers are not recoverable and " "this deletion will delete all of the sub-resources." msgstr[0] "" "You have selected \"%s\". Deleted load balancer is not recoverable and this " "deletion will delete all of the sub-resources." msgstr[1] "" "You have selected \"%s\". Deleted load balancers are not recoverable and " "this deletion will delete all of the sub-resources." #, python-format msgid "You have selected \"%s\". Deleted member is not recoverable." msgid_plural "You have selected \"%s\". Deleted members are not recoverable." msgstr[0] "You have selected \"%s\". Deleted member is not recoverable." msgstr[1] "You have selected \"%s\". Deleted members are not recoverable." #, python-format msgid "You have selected \"%s\". Deleted pool is not recoverable." msgid_plural "You have selected \"%s\". Deleted pools are not recoverable." msgstr[0] "You have selected \"%s\". Deleted pool is not recoverable." msgstr[1] "You have selected \"%s\". Deleted pools are not recoverable." ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.453101 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/es/0000775000175100017510000000000015033037476022515 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/es/LC_MESSAGES/0000775000175100017510000000000015033037476024302 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/es/LC_MESSAGES/django.po0000664000175100017510000000116715033037474026107 0ustar00mylesmyles# Alberto Molina Coballes , 2021. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2021-03-25 18:29+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2021-06-07 06:04+0000\n" "Last-Translator: Alberto Molina Coballes \n" "Language-Team: Spanish\n" "Language: es\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "Load Balancers" msgstr "Balanceadores de carga" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.453101 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/fr/0000775000175100017510000000000015033037476022515 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/fr/LC_MESSAGES/0000775000175100017510000000000015033037476024302 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/fr/LC_MESSAGES/django.po0000664000175100017510000001410215033037474026100 0ustar00mylesmyles# Gérald LONLAS , 2016. #zanata # Corinne Verheyde , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard 1.0.1.dev52\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2017-01-26 23:11+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-01-29 11:01+0000\n" "Last-Translator: Corinne Verheyde \n" "Language-Team: French\n" "Language: fr\n" "X-Generator: Zanata 3.7.3\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" #, python-format msgid "%s loadbalancers" msgstr "%s répartiteurs de charge" msgid "Admin Status" msgstr "Statut admin" msgid "All Instances" msgstr "Toutes les instances" msgid "Certificate" msgstr "Certificat" msgid "Certificate Name" msgstr "Nom du certificat" msgid "Could not create full loadbalancer." msgstr "Impossible de créer un répartiteurs de charge complet" msgid "Could not get load balancer list." msgstr "Impossible de charger la liste des répartiteurs de charge" msgid "Disable" msgstr "Désactiver" msgid "Disabled LB" msgstr "Désactiver le LB" msgid "Edit Load Balancer" msgstr "Éditer le répartiteur de charge" msgid "Enable" msgstr "Activer" msgid "Enabled LB" msgstr "Activer le LB" msgid "HTTP" msgstr "HTTP" msgid "HTTPS" msgstr "HTTPS" msgid "Health Check Interval (in seconds)" msgstr "Interval (en secondes) de l'état de santé" msgid "IP" msgstr "IP" msgid "Instance Port" msgstr "Port de l'instance" msgid "Instance Port on which service is running." msgstr "Port de l'instance sur lequel le service tourne." msgid "Instances" msgstr "Instances" msgid "LB Details" msgstr "Détails du LB" msgid "LB Port" msgstr "Port du LB" msgid "LB Port on which LB is listening." msgstr "Port sur lequel le LB écoute" msgid "LB Protocol" msgstr "Protocole du LB" msgid "Launch" msgstr "Démarrer" msgid "Launch Load Balancer" msgstr "Démarrer le répartiteur de charge" #, python-format msgid "Launched %(count)s named \"%(name)s\"." msgstr "%(count)s instance(s) nommée(s) \"%(name)s\" ont été lancée(s)." msgid "Load Balancer" msgstr "Répartiteur de charge" msgid "Load Balancer Description" msgstr "Description du répartiteur de charge" msgid "Load Balancers" msgstr "Répartiteurs de charge" msgid "Load Balancers V2" msgstr "Répartiteurs de charge V2" msgid "Load Balancing Method" msgstr "Méthode d'équilibrage de charge" msgid "Method" msgstr "Méthode" msgid "Monitor" msgstr "Moniteur" msgid "Name" msgstr "Nom" msgid "No instances found." msgstr "Aucune instance trouvée." msgid "No members enabled." msgstr "Aucun membre activé." msgid "Not available" msgstr "Non disponible" msgid "" "Number of times health check should be attempted before marking down a member" msgstr "" "Nombre de fois où nous devons vérifier l'état de santé avant de marquer le " "membre comme mort." msgid "Operating Status" msgstr "Statut opérationnel" msgid "Overview" msgstr "Vue d'ensemble" msgid "PING" msgstr "PING" msgid "Please provide all certificate parameters." msgstr "Merci de fournir tous les paramètres du certificat." msgid "Please provide instance port" msgstr "Merci de fournir le port de l'instance" msgid "Please select an option for the load balancing method." msgstr "Sélectionner une option pour la méthode de répartition de charge." msgid "Please select at least one member" msgstr "Merci de sélectionner au moins un membre" msgid "Private Key" msgstr "Clé privée" msgid "Protocol" msgstr "Protocole" msgid "Provide Load Balancer Description." msgstr "Fournir une description pour le répartiteur de charge" msgid "Provisioning Status" msgstr "Statut de Déploiement" msgid "Receive String" msgstr "Chaine de caractères reçue" #, fuzzy msgid "Retry count before markdown" msgstr "Nombre d'essai avant de marquer" msgid "Round Robin" msgstr "Round Robin" msgid "SSL" msgstr "pas de support du ssl" msgid "SSL Certificate" msgstr "Certificat SSL" msgid "Scheduled termination of" msgstr "Planification de la fin de" msgid "Select from existing VIP IPs" msgstr "Sélection depuis les IPs VIP existantes" msgid "Selected Instances" msgstr "Instances selectionnées" msgid "Send String" msgstr "Chaine de caractères envoyée" msgid "TCP" msgstr "TCP" msgid "Terminate" msgstr "Terminé" #, python-format msgid "Unable to get VIP for pool %(pool)s." msgstr "Impossible d'obtenir une adresse IP virtuelle pour le pool %(pool)s." #, python-format msgid "Unable to get health monitors for pool %(pool)s." msgstr "Impossible d'obtenir le moniteur de santé pour le pool %(pool)s." #, python-format msgid "Unable to get members for pool %(pool)s." msgstr "Impossible d'obtenir les membres pour le pool %(pool)s." msgid "Unable to get pool detail." msgstr "Impossible d'obtenir les informations sur le pool." #, python-format msgid "Unable to get subnet for pool %(pool)s." msgstr "Impossible d'obtenir le sous-réseau pour le pool %(pool)s." #, python-format msgid "Unable to launch %(count)s named \"%(name)s\"." msgstr "Impossible de démarrer %(count)s instance(s) nommée(s) \"%(name)s\"." #, python-format msgid "Unable to modify load balancer \"%s\"." msgstr "Impossible de modifier le répartiteur de charge \"%s\"." #, python-format msgid "Unable to retrieve details for loadbalancer \"%s\"." msgstr "" "Impossible de récupérer les détails pour le répartiteur de charge \"%s\"." #, python-format msgid "Unable to retrieve load balancer details. %s" msgstr "Impossible de récupérer les détails du répartiteur de charge. %s" msgid "Unable to retrieve members list. Please try again later." msgstr "" "Impossible de récupérer la liste des membres. Veuillez réessayer plus tard." msgid "Unable to retrieve pools list." msgstr "Impossible de récupérer la liste des pools." msgid "Unable to retrieve vips." msgstr "Impossible de récupérer les VIPs." msgid "Update" msgstr "Mettre à jour" #, python-format msgid "Updated load balancer \"%s\"." msgstr "Répartiteur de charge mis à jour \"%s\"." msgid "loadbalancer" msgstr "répartiteur de charge" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.453101 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/id/0000775000175100017510000000000015033037476022502 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/id/LC_MESSAGES/0000775000175100017510000000000015033037476024267 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/id/LC_MESSAGES/django.po0000664000175100017510000000113515033037474026067 0ustar00mylesmyles# suhartono , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2018-03-03 16:54+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-02-21 05:26+0000\n" "Last-Translator: suhartono \n" "Language-Team: Indonesian\n" "Language: id\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "Load Balancers" msgstr "Load Balancers" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/id/LC_MESSAGES/djangojs.po0000664000175100017510000011664615033037474026442 0ustar00mylesmyles# suhartono , 2018. #zanata # suhartono , 2019. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2022-08-16 20:34+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2019-07-17 04:17+0000\n" "Last-Translator: suhartono \n" "Language-Team: Indonesian\n" "Language: id\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" #, python-format msgid "%(ip)s..." msgstr "%(ip)s..." msgid "A new health monitor is being created." msgstr "Monitor kesehatan baru sedang dibuat." msgid "A new l7 policy is being created." msgstr "Kebijakan l7 baru sedang dibuat." msgid "A new listener is being created." msgstr "Pendengar (listener) baru sedang dibuat." msgid "A new load balancer is being created." msgstr "Penyeimbang beban baru sedang dibuat." msgid "A new pool is being created." msgstr "Pool baru sedang dibuat." msgid "" "A pool represents a group of members over which the load balancing will be " "applied." msgstr "" "Sebuah pool mewakili sekelompok anggota dimana load balancing akan " "diterapkan." msgid "APP_COOKIE: Session persistence based on application cookie." msgstr "APP_COOKIE: Sesi persistensi berdasarkan aplikasi cookie." msgid "Action" msgstr "Action" msgid "Action:" msgstr "Action:" msgid "Active" msgstr "Active" msgid "Add" msgstr "Menambahkan" msgid "Add external member" msgstr "Tambahkan anggota eksternal" msgid "Add members to the load balancer pool." msgstr "Tambahkan anggota ke load balancer pool." msgid "Add/Remove Members" msgstr "Add/Remove Members" msgid "Add/Remove Pool Members" msgstr "Add/Remove Pool Members" msgid "" "Additional headers insertion into HTTP header,\n" " only \"X-Forwarded-For\", \"X-Forwarded-Port\" and \"X-Forwarded-Proto\" " "are supported." msgstr "" "Tambahan headers ke dalam headers HTTP,\n" "   hanya \"X-Forwarded-For\", \"X-Forwarded-Port\" dan \"X-Forwarded-Proto\" " "didukung." msgid "Admin State Up" msgstr "Admin State Up" msgid "Algorithm" msgstr "Algorithm" msgid "Algorithm:" msgstr "Algoritma:" msgid "Allocated Members" msgstr "Allocated Members" msgid "" "An L7 Policy is a collection of L7 rules associated with a Listener, and " "which may also have an association to a back-end pool" msgstr "" "Kebijakan L7 adalah kumpulan aturan L7 yang terkait dengan Listener, dan " "yang mungkin juga memiliki asosiasi ke kumpulan back-end" msgid "" "An L7 Rule is a single, simple logical test which returns either true or\n" "false." msgstr "" "Aturan L7 adalah tes logis tunggal, sederhana yang mengembalikan baik benar " "atau salah." msgid "" "An alternate IP address used for health monitoring a backend member.\n" " Default is null which monitors the member address." msgstr "" "Alamat IP alternatif yang digunakan untuk memantau kesehatan anggota " "backend.\n" "   Default adalah null yang memonitor alamat anggota." msgid "" "An alternate protocol port used for health monitoring a backend member.\n" " Default is null which monitors the member protocol port." msgstr "" "Port protokol alternatif yang digunakan untuk pemantauan kesehatan anggota " "backend.\n" "   Default adalah null yang memonitor port protokol anggota." msgid "An error occurred. Please try again later." msgstr "Terjadi kesalahan. Silakan coba lagi nanti." msgid "Associate" msgstr "Associate" msgid "Associate Floating IP" msgstr "Associate Floating IP" msgid "Associate Floating IP Address" msgstr "Associate Floating IP Address" msgid "Associating floating IP with load balancer." msgstr "Mengaitkan IP mengambang dengan penyeimbang beban." msgid "Available Instances" msgstr "Available Instances" msgid "Backend member connection timeout in milliseconds. Default: 5000." msgstr "Waktu koneksi anggota backend dalam milidetik. Default: 5000." msgid "Backend member inactivity timeout in milliseconds. Default: 50000." msgstr "Waktu tidak aktif anggota backend dalam milidetik. Default: 50000." msgid "Backup" msgstr "Backup (cadangan)" msgid "Backup:" msgstr "Backup (cadangan):" msgid "CIDR" msgstr "CIDR" msgid "CONTAINS: String contains." msgstr "CONTAINS: String mengandung." msgid "" "COOKIE: The rule looks for a cookie named by the key parameter and\n" " compares it against the value parameter in the rule." msgstr "" "COOKIE: Aturan mencari cookie yang dinamai oleh parameter kunci dan " "membandingkannya dengan parameter nilai dalam aturan." msgid "Cancel" msgstr "Cancel" msgid "Certificate Name" msgstr "Certificate Name" msgid "Client Data Timeout" msgstr "Client Data Timeout (batas waktu data klien)" msgid "Client Data Timeout:" msgstr "Batas Waktu Data Klien:" msgid "Compare Type" msgstr "Compare Type" msgid "Compare Type:" msgstr "Compare Type:" msgid "Confirm Delete Health Monitor" msgid_plural "Confirm Delete Health Monitors" msgstr[0] "Confirm Delete Health Monitor" msgid "Confirm Delete L7 Policy" msgid_plural "Confirm Delete L7 Policies" msgstr[0] "Confirm Delete L7 Policy" msgid "Confirm Delete L7 Rule" msgid_plural "Confirm Delete L7 Rules" msgstr[0] "Confirm Delete L7 Rule" msgid "Confirm Delete Listener" msgid_plural "Confirm Delete Listeners" msgstr[0] "Confirm Delete Listener" msgid "Confirm Delete Load Balancer" msgid_plural "Confirm Delete Load Balancers" msgstr[0] "Confirm Delete Load Balancer" msgid "Confirm Delete Member" msgid_plural "Confirm Delete Members" msgstr[0] "Confirm Delete Member" msgid "Confirm Delete Pool" msgid_plural "Confirm Delete Pools" msgstr[0] "Confirm Delete Pool" msgid "Confirm Disassociate Floating IP Address" msgstr "Konfirmasikan Disassociate Floating IP Address" msgid "Connection Limit" msgstr "Connection Limit" msgid "Connection Limit:" msgstr "Connection Limit:" msgid "Contains" msgstr "Contains" msgid "Cookie" msgstr "Cookie" msgid "Cookie Name" msgstr "Cookie Name" msgid "Create Health Monitor" msgstr "Create Health Monitor" msgid "Create L7 Policy" msgstr "Buat Kebijakan L7" msgid "Create L7 Rule" msgstr "Buat Aturan L7" msgid "Create Listener" msgstr "Create Listener" msgid "Create Load Balancer" msgstr "Membuat Load Balancer" msgid "Create Pool" msgstr "Create Pool" msgid "Created At" msgstr "Created At" msgid "Default Pool ID" msgstr "Default Pool ID" msgid "Default Pool ID:" msgstr "Default Pool ID:" msgid "Default TLS Container Ref" msgstr "Default TLS Container Ref" msgid "Degraded" msgstr "Degraded" msgid "Delay" msgstr "Delay" msgid "Delay (sec)" msgstr "Delay (sec)" msgid "Delay:" msgstr "Delay:" msgid "Delete Health Monitor" msgid_plural "Delete Health Monitors" msgstr[0] "Delete Health Monitor" msgid "Delete Health Monitors" msgstr "Delete Health Monitors" msgid "Delete L7 Policies" msgstr "Hapus Kebijakan L7" msgid "Delete L7 Policy" msgid_plural "Delete L7 Policies" msgstr[0] "Delete L7 Policy" msgid "Delete L7 Rule" msgid_plural "Delete L7 Rules" msgstr[0] "Delete L7 Rule" msgid "Delete L7 Rules" msgstr "Hapus Aturan L7" msgid "Delete Listener" msgid_plural "Delete Listeners" msgstr[0] "Delete Listener" msgid "Delete Listeners" msgstr "Delete Listeners" msgid "Delete Load Balancer" msgid_plural "Delete Load Balancers" msgstr[0] "Delete Load Balancer" msgid "Delete Load Balancers" msgstr "Menghapus Load Balancers" msgid "Delete Member" msgid_plural "Delete Members" msgstr[0] "Delete Member" msgid "Delete Members" msgstr "Delete Members" msgid "Delete Pool" msgid_plural "Delete Pools" msgstr[0] "Delete Pool" msgid "Delete Pools" msgstr "Delete Pools" #, python-format msgid "Deleted Health Monitor: %s." msgid_plural "Deleted Health Monitors: %s." msgstr[0] "Deleted Health Monitor: %s." #, python-format msgid "Deleted L7 Policy: %s." msgid_plural "Deleted L7 Policies: %s." msgstr[0] "Deleted L7 Policy: %s." #, python-format msgid "Deleted L7 Rule: %s." msgid_plural "Deleted L7 Rules: %s." msgstr[0] "Deleted L7 Rule: %s." #, python-format msgid "Deleted Listener: %s." msgid_plural "Deleted Listeners: %s." msgstr[0] "Deleted Listener: %s." #, python-format msgid "Deleted Load Balancer: %s." msgid_plural "Deleted Load Balancers: %s." msgstr[0] "Deleted Load Balancer: %s." #, python-format msgid "Deleted Member: %s." msgid_plural "Deleted Members: %s." msgstr[0] "Deleted Member: %s." #, python-format msgid "Deleted Pool: %s." msgid_plural "Deleted Pools: %s." msgstr[0] "Deleted Pool: %s." msgid "Description" msgstr "Deskripsi" msgid "Disassociate" msgstr "Disassociate" msgid "Disassociate Floating IP" msgstr "Disassociate Floating IP" #, python-format msgid "Disassociated floating IP address from load balancer: %s." msgstr "Alamat IP mengambang yang dipisahkan dari load balancer: %s." msgid "ENDS_WITH: String ends with." msgstr "ENDS_WITH: String berakhir dengan." msgid "EQUAL_TO: String is equal to." msgstr "EQUAL_TO: String sama dengan." msgid "" "Each port that listens for traffic on a particular load balancer is " "configured separately and\n" " tied to the load balancer. Multiple listeners can be associated with the " "same load balancer but\n" " each must use a unique port." msgstr "" "Setiap port yang mendengarkan lalu lintas pada load balancer tertentu " "dikonfigurasi secara terpisah dan\n" "   terkait dengan load balancer. Beberapa listener dapat dikaitkan dengan " "load balancer yang sama namun\n" "   masing harus menggunakan port yang unik." msgid "Edit Health Monitor" msgstr "Edit Health Monitor" msgid "Edit L7 Policy" msgstr "Edit Kebijakan L7" msgid "Edit L7 Rule" msgstr "Edit Aturan L7" msgid "Edit Listener" msgstr "Edit Listener" msgid "Edit Load Balancer" msgstr "Edit Load Balancer" msgid "Edit Member" msgstr "Edit Member" msgid "Edit Pool" msgstr "Edit Pool" msgid "Ends With" msgstr "Ends With" msgid "Equal To" msgstr "Equal To" msgid "Error" msgstr "Error" msgid "Expected Codes" msgstr "Expected Codes" msgid "Expected Codes:" msgstr "Expected Codes:" msgid "Expiration Date" msgstr "Expiration Date" msgid "" "FILE_TYPE: The rule compares the last portion of the URI against\n" " the value parameter in the rule. (eg. \"txt\", \"jpg\", etc.)" msgstr "" "FILE_TYPE: Aturannya membandingkan bagian terakhir dari URI terhadap\n" "       parameter nilai dalam aturan. (eg. \"txt\", \"jpg\", etc.)" msgid "File Type" msgstr "File Type" msgid "Flavor" msgstr "Flavor" msgid "Flavor Description" msgstr "Deskripsi Flavor" msgid "Flavor ID" msgstr "Flavor ID" msgid "Floating IP" msgstr "Floating IP" msgid "Floating IP address or pool" msgstr "Mengambang alamat IP atau pool" msgid "Floating IP addresses" msgstr "Floating IP addresses" msgid "Floating IP pools" msgstr "Floating IP pools" msgid "Frontend client inactivity timeout in milliseconds. Default: 50000." msgstr "" "Batas waktu ketidakstabilan klien frontend dalam milidetik. Default: 50000." msgid "" "HEADER: The rule looks for a header defined in the key parameter\n" " and compares it against the value parameter in the rule." msgstr "" "HEADER: Aturan mencari header yang ditentukan dalam parameter kunci dan " "membandingkannya dengan parameter nilai dalam aturan." msgid "" "HOST_NAME: The rule does a comparison between the HTTP/1.1\n" " hostname in the request against the value parameter in the rule." msgstr "" "HOST_NAME: Aturan melakukan perbandingan antara HTTP / 1.1 nama host dalam " "permintaan terhadap parameter nilai dalam aturan." msgid "HTTP Method" msgstr "HTTP Method" msgid "HTTP Method:" msgstr "HTTP Method:" msgid "HTTP_COOKIE: Session persistence based on http cookie." msgstr "HTTP_COOKIE: Sesi persistensi berdasarkan http cookie." msgid "Header" msgstr "Header" msgid "Health Monitor" msgstr "Health Monitor" msgid "Health Monitor ID" msgstr "Health Monitor ID" msgid "Health Monitors" msgstr "Health Monitors" msgid "Host Name" msgstr "Host Name" msgid "ID" msgstr "ID" msgid "IP Address" msgstr "IP Address" #, python-format msgid "IP Addresses (%(count)s)" msgstr "IP Addresses (%(count)s)" msgid "IP address" msgstr "IP address" msgid "IP address:" msgstr "IP address (alamat IP):" msgid "" "If an IP address is provided it must be a well-formed IPv4 or IPv6 address. " "The system will\n" " attempt to assign the provided IP address to the load balancer. If an IP " "address is not provided\n" " then one will be allocated for you." msgstr "" "Jika alamat IP disediakan maka alamat IPv4 atau IPv6 akan terjalin dengan " "baik. Sistem akan\n" "   mencoba untuk menetapkan alamat IP yang diberikan ke penyeimbang beban. " "Jika alamat IP tidak tersedia\n" "   maka satu akan dialokasikan untuk Anda." msgid "" "If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL " "certificates must\n" " be selected. The first certificate will be the default." msgstr "" "Jika listener menggunakan protokol TERMINATED_HTTPS, maka satu atau beberapa " "sertifikat SSL harus\n" "   dipilih. Sertifikat pertama akan menjadi default." msgid "Inactive" msgstr "Inactive" msgid "Insert Headers" msgstr "Memasukkan Headers" msgid "Insert Headers:" msgstr "Insert Headers:" msgid "Invert" msgstr "Invert" msgid "Invert:" msgstr "Invert:" msgid "" "Is the member a backup? Backup members only receive traffic when all\n" " non-backup members are down." msgstr "" "Apakah anggota itu cadangan? Anggota cadangan hanya menerima lalu lintas " "saat semua\n" "   anggota non-cadangan mati." msgid "Key" msgstr "Key" msgid "Key Manager API Guide: Creating a Certificate Container" msgstr "Key Manager API Guide: Creating a Certificate Container" msgid "Key Manager Service Command-Line Client" msgstr "Key Manager Service Command-Line Client" msgid "Key:" msgstr "Key:" msgid "L7 Policies" msgstr "L7 Policies" msgid "L7 Policy" msgstr "Kebijakan L7" msgid "L7 Policy Details" msgstr "L7 Policy Details" msgid "L7 Rule" msgstr "Peraturan L7" msgid "L7 Rule Details" msgstr "L7 Rule Details" msgid "L7 Rules" msgstr "Peraturan L7" msgid "" "LEAST_CONNECTIONS: Allocates requests to the instance with the least number " "of active\n" " connections." msgstr "" "LEAST_CONNECTIONS: Alokasikan permintaan ke instance dengan jumlah paling " "sedikit yang aktif\n" "       koneksi." msgid "Least Connections" msgstr "Least Connections" msgid "Listener" msgstr "Listener" msgid "Listener Details" msgstr "Listener Details" msgid "Listener ID" msgstr "Listener ID" msgid "Listeners" msgstr "Listeners" msgid "Load Balancer" msgstr "Load Balancer" msgid "Load Balancer Details" msgstr "Load Balancer Details" msgid "Load Balancers" msgstr "Load Balancers" msgid "Loading" msgstr "Loading" msgid "Max Retries" msgstr "Max Retries" msgid "Max Retries Down" msgstr "Max Retries Down" msgid "Max Retries Down:" msgstr "Max Retries Down:" msgid "Max Retries:" msgstr "Max Retries:" msgid "Member" msgstr "Member" msgid "Member Connect Timeout" msgstr "Member Connect Timeout (batas waktu koneksi anggota)" msgid "Member Connect Timeout:" msgstr "Member Connect Timeout (batas waktu data anggota):" msgid "Member Data Timeout" msgstr "Member Data Timeout (batas waktu data anggota)" msgid "Member Data Timeout:" msgstr "Member Data Timeout (batas waktu data anggota):" msgid "Members" msgstr "Members" msgid "" "Members are the actual IP addresses that will receive traffic from the load " "balancer. Each\n" " member must have a unique combination of IP address and port." msgstr "" "Members adalah alamat IP sebenarnya yang akan menerima lalu lintas dari " "penyeimbang beban. Setiap\n" "   member harus memiliki kombinasi unik dari alamat IP dan port." msgid "Monitor Address" msgstr "Monitor Address" msgid "Monitor Address:" msgstr "Monitor Address:" msgid "Monitor Details" msgstr "Monitor Details" msgid "Monitor Port" msgstr "Monitor Port" msgid "Monitor Port:" msgstr "Monitor Port:" msgid "Name" msgstr "Name" msgid "Network" msgstr "Network" msgid "Network ID" msgstr "Network ID" msgid "No" msgstr "No" msgid "No Monitor" msgstr "No Monitor" msgid "No available certificates" msgstr "Tidak ada sertifikat yang tersedia" msgid "No available instances" msgstr "Tidak ada instance yang tersedia" msgid "No items to display." msgstr "Tidak ada item untuk ditampilkan." msgid "No matching options" msgstr "Tidak ada opsi yang cocok" msgid "No members have been allocated" msgstr "Tidak ada anggota (member) yang dialokasikan" msgid "None" msgstr "None" msgid "Offline" msgstr "Offline" msgid "Online" msgstr "Online" msgid "Operating Status" msgstr "Operating Status" msgid "Overview" msgstr "Overview" msgid "" "PATH: The rule compares the path portion of the HTTP URI against\n" " the value parameter in the rule." msgstr "" "PATH: Aturan membandingkan bagian path HTTP URI dengan parameter nilai dalam " "aturan." msgid "Path" msgstr "Path" msgid "Pending Create" msgstr "Pending Create" msgid "Pending Delete" msgstr "Pending Delete" msgid "Pending Update" msgstr "Pending Update" msgid "Please Wait" msgstr "Please Wait" msgid "Pool" msgstr "Pool" msgid "Pool Details" msgstr "Pool Details" msgid "Pool Members" msgstr "Pool Members" msgid "Pool member has been updated." msgstr "Anggota pool telah diperbarui." msgid "Pools" msgstr "Pool" msgid "Port" msgstr "Port" msgid "Port ID" msgstr "Port ID" msgid "Port:" msgstr "Port:" msgid "Position" msgstr "Position" msgid "Position:" msgstr "Posisi:" msgid "Project" msgstr "Project" msgid "Project ID" msgstr "Project ID" msgid "Protocol" msgstr "Protocol" msgid "Protocol Port" msgstr "Protocol Port" msgid "Protocol:" msgstr "Protocol:" msgid "Provide the details for the health monitor." msgstr "Berikan detil untuk monitor kesehatan." msgid "Provide the details for the l7 policy." msgstr "Berikan detail untuk kebijakan l7." msgid "Provide the details for the l7 rule." msgstr "Berikan detail untuk aturan l7." msgid "Provide the details for the listener." msgstr "Berikan detil untuk listener." msgid "Provide the details for the load balancer." msgstr "Berikan detil untuk penyeimbang beban." msgid "Provide the details for the member." msgstr "Berikan detail untuk anggota." msgid "Provide the details for the pool." msgstr "Berikan rincian untuk pool." msgid "Provider" msgstr "Provider" msgid "Provisioning Status" msgstr "Provisioning Status" msgid "" "REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated " "with the L7 policy." msgstr "" "REDIRECT_TO_POOL: Permintaan diteruskan ke kumpulan back-end yang terkait " "dengan kebijakan L7." msgid "" "REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in " "the redirect_url parameter." msgstr "" "REDIRECT_TO_URL: Permintaan dikirim redirect HTTP ke URL yang ditentukan " "dalam parameter redirect_url." msgid "REGEX: Perl type regular expression matching." msgstr "REGEX: Pencocokan ekspresi reguler tipe Perl." msgid "" "REJECT: The request is denied with an appropriate response code, and not " "forwarded on to any back-end pool." msgstr "" "REJECT: Permintaan ditolak dengan kode respons yang sesuai, dan tidak " "diteruskan ke kumpulan back-end apa pun." msgid "ROUND_ROBIN: Rotates requests evenly between multiple instances." msgstr "" "ROUND_ROBIN: Memutar permintaan secara merata di antara beberapa instance." msgid "Redirect Pool ID" msgstr "Redirect Pool ID" msgid "Redirect Pool ID:" msgstr "Redirect Pool ID:" msgid "Redirect URL" msgstr "Redirect URL" msgid "Redirect URL:" msgstr "Redirect URL:" msgid "Redirect to Pool" msgstr "Redirect to Pool" msgid "Redirect to URL" msgstr "Redirect to URL" msgid "Regex" msgstr "Regex" msgid "Reject" msgstr "Reject" msgid "Remove" msgstr "Remove" msgid "" "Requests matching this policy will be redirected to the pool with this ID. " "Only valid if action is REDIRECT_TO_POOL." msgstr "" "Permintaan yang cocok dengan kebijakan ini akan dialihkan ke kumpulan dengan " "ID ini. Hanya valid jika tindakan REDIRECT_TO_POOL." msgid "" "Requests matching this policy will be redirected to this URL. Only valid if " "action is REDIRECT_TO_URL." msgstr "" "Permintaan yang cocok dengan kebijakan ini akan dialihkan ke URL ini. Hanya " "valid jika tindakan REDIRECT_TO_URL." msgid "Round Robin" msgstr "Round Robin" msgid "Rules" msgstr "Rules" msgid "SNI Container Refs" msgstr "SNI Container Refs" msgid "" "SOURCE_IP: Requests from a unique source IP address are consistently " "directed to the same instance." msgstr "" "SOURCE_IP: Permintaan dari alamat IP sumber unik secara konsisten diarahkan " "ke instance yang sama." msgid "SOURCE_IP: Session persistence based on source ip." msgstr "SOURCE_IP:Sesi persistensi berbasis sumber ip." msgid "SSL Certificates" msgstr "SSL Certificates" msgid "STARTS_WITH: String starts with." msgstr "STARTS_WITH: String dimulai dengan." msgid "" "Select a floating IP address to associate with the load balancer or a " "floating IP pool in which to allocate a new floating IP address." msgstr "" "Pilih alamat IP mengambang (floating IP address) untuk diasosiasikan dengan " "penyeimbang beban (load balancer) atau kolam IP mengambang di mana untuk " "mengalokasikan alamat IP mengambang baru." msgid "Select certificates from the available certificates below" msgstr "Pilih sertifikat dari sertifikat yang tersedia di bawah ini" msgid "Select one or more SSL certificates for the listener." msgstr "Pilih satu atau beberapa sertifikat SSL untuk pendengarnya." msgid "Session Persistence" msgstr "Session Persistence" msgid "Session Persistence:" msgstr "Session Persistence (sesi persistensi):" msgid "Source IP" msgstr "Source IP" msgid "Starts With" msgstr "Starts With" msgid "Subnet" msgstr "Subnet" msgid "Subnet ID" msgstr "Subnet ID" msgid "Subnet:" msgstr "Subnet:" msgid "TCP Inspect Timeout" msgstr "TCP Inspect Timeout (batas waktu periksa TCP)" msgid "TCP Inspect Timeout:" msgstr "TCP Inspect Timeout (batas waktu periksa TCP):" msgid "" "The Available Instances table contains existing compute instances that can " "be added as members\n" " of the pool. Use the \"Add external member\" button to add a member not " "found in the Available\n" " Instances table." msgstr "" "Table Available Instances berisi Instance perhitungan yang ada yang dapat " "ditambahkan sebagai member\n" "   dari pool. Gunakan tombol \"Add external member\" untuk menambahkan " "member yang tidak ditemukan di tabel Available\n" "   Instances." msgid "The HTTP method used to perform the health check." msgstr "Metode HTTP digunakan untuk melakukan pemeriksaan kesehatan." msgid "The ID of the pool used by the listener if no L7 policies match." msgstr "" "ID dari pool yang digunakan oleh pendengar (listener) jika tidak ada " "kebijakan L7 yang cocok." msgid "The IP address is not valid." msgstr "Alamat IP tidak valid." msgid "" "The IP address of the member to receive traffic from the load balancer. Must " "be a well-formed\n" " IPv4 or IPv6 address." msgstr "" "Alamat IP member untuk menerima lalu lintas dari penyeimbang beban (load " "balancer). Harus menjadi well-formed\n" "   Alamat IPv4 atau IPv6" msgid "" "The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL." msgstr "" "Tindakan kebijakan L7. Salah satu REJECT, REDIRECT_TO_URL, atau " "REDIRECT_TO_POOL." msgid "The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH." msgstr "" "The L7 rule type. Salah satu COOKIE, FILE_TYPE, HEADER, HOST_NAME, atau PATH." msgid "The URL path is not valid." msgstr "URL path tidak valid." msgid "" "The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, or STARTS_WITH." msgstr "" "The comparison type untuk aturan L7. Salah satu CONTAINS, ENDS_WITH,\n" "   EQUAL_TO, REGEX, atau STARTS_WITH." msgid "The connection limit must be a number greater than or equal to -1." msgstr "" "Batas koneksi harus berupa angka yang lebih besar dari atau sama dengan -1." msgid "" "The expected HTTP status codes to get from a successful health check. Must " "be a single number,\n" " a comma separated list of numbers, or a range (two numbers separated by a " "hyphen)." msgstr "" "Kode status HTTP yang diharapkan dapat diperoleh dari pemeriksaan kesehatan " "yang berhasil. Harus nomor tunggal,\n" "   daftar bilangan koma yang dipisahkan, atau kisaran (dua angka yang " "dipisahkan oleh tanda hubung)." msgid "The expected status code is not valid." msgstr "Kode status yang diharapkan tidak valid." msgid "The health check interval must be greater than or equal to the timeout." msgstr "" "Interval pemeriksaan kesehatan harus lebih besar dari atau sama dengan batas " "waktu." msgid "The health monitor has been updated." msgstr "Health Monitor telah diperbarui." msgid "" "The health monitor is used to determine the health of your pool members. " "Health checks\n" " routinely run against each member within the pool and the result of the " "health check is used\n" " to determine if the member receives new connections. Each pool can only " "have one health\n" " monitor." msgstr "" "Monitor kesehatan digunakan untuk menentukan kesehatan pool member Anda. Cek " "kesehatan\n" "   secara rutin jalankan terhadap setiap anggota di dalam kolam dan hasil " "pemeriksaan kesehatan digunakan\n" "   untuk menentukan apakah anggota menerima koneksi baru. Setiap pool hanya " "bisa memiliki satu kesehatan\n" "   monitor." msgid "" "The interval between health checks. Must be greater than or equal to the " "timeout." msgstr "" "Selang waktu antara pemeriksaan kesehatan. Harus lebih besar dari atau sama " "dengan timeout." msgid "" "The key to use for the comparison. For example, the name of the cookie\n" " to evaluate." msgstr "" "The key untuk digunakan sebagai pembanding. Misalnya, nama cookie untuk " "mengevaluasi." msgid "The l7policy has been updated." msgstr "Kebijakan l7 telah diperbarui." msgid "The l7rule has been updated." msgstr "L7rule telah diperbarui." msgid "The listener has been updated." msgstr "The listener has been updated." msgid "" "The load balancer algorithm that distributes traffic to the pool members." msgstr "" "Algoritma load balancer yang mendistribusikan lalu lintas ke pool member." msgid "The load balancer has been updated." msgstr "Load balancer telah diperbarui." msgid "" "The load balancer occupies a neutron network port and has an IP address " "assigned from a subnet." msgstr "" "Penyeimbang beban (load balancer) menempati port jaringan neutron dan " "memiliki alamat IP yang ditetapkan dari subnet." msgid "The max retry count must be a number between 1 and 10." msgstr "Count coba ulang maksimum harus berupa angka antara 1 dan 10." msgid "The max retry down count must be a number between 1 and 10." msgstr "Down count coba ulang maksimum harus berupa angka antara 1 dan 10." msgid "" "The maximum number of connections permitted for this listener.\n" " Default value is -1 which represents infinite connections." msgstr "" "Jumlah maksimum koneksi yang diizinkan untuk listener ini.\n" "   Nilai default adalah -1 yang mewakili koneksi tak terbatas." msgid "The monitor address must be a valid IP address." msgstr "Alamat monitor harus merupakan alamat IP yang valid." msgid "The monitor port must be a number between 1 and 65535." msgstr "Port monitor harus berupa angka antara 1 dan 65535." msgid "The network on which to allocate the load balancer's IP address." msgstr "Jaringan untuk mengalokasikan alamat IP penyeimbang beban." msgid "The network which contains the IP address of the member." msgstr "Jaringan yang berisi alamat IP member." msgid "" "The number of allowed connection failures before marking the member as " "error. Must be a\n" " number from 1 to 10. The default is 3." msgstr "" "Jumlah kegagalan koneksi yang diijinkan sebelum menandai member sebagai " "error. Harus \n" "   nomor dari 1 sampai 10. Defaultnya adalah 3." msgid "" "The number of allowed connection failures before marking the member as " "inactive. Must be a\n" " number from 1 to 10." msgstr "" "Jumlah kegagalan koneksi yang diizinkan sebelum menandai anggota sebagai " "tidak aktif. Harus \n" "   nomor dari 1 sampai 10." msgid "The pool has been updated." msgstr "Pool telah diperbarui." msgid "The pool members have been updated." msgstr "Anggota pool telah diperbarui." msgid "The port must be a number between 1 and 65535." msgstr "Port harus berupa angka antara 1 dan 65535." msgid "" "The port must be unique among all listeners attached to this load balancer." msgstr "" "Port harus unik di antara semua listener yang terpasang pada load balancer " "ini." msgid "" "The port on which the front end listens. Must be an integer from 1 to 65535." msgstr "" "Port yang ujung depannya mendengarkan. Harus bilangan bulat dari 1 sampai " "65535." msgid "" "The port on which the member listens for traffic. Must be a number from 1 to " "65535." msgstr "" "Port di mana anggota (member) mendengarkan lalu lintas. Harus nomor dari 1 " "sampai 65535." msgid "The position must be a number between 1 and 2147483647." msgstr "Posisi harus berupa angka antara 1 dan 2147483647." msgid "The position of this policy on the listener. Positions start at 1." msgstr "Posisi kebijakan ini pada pendengar. Posisi mulai 1." msgid "" "The protocol for which the front end listens. The TERMINATED_HTTPS protocol " "is only available if\n" " the key-manager service is enabled and you have authority to list " "certificate containers and\n" " secrets." msgstr "" "Protokol yang ujung depannya mendengarkan. Protokol TERMINATED_HTTPS hanya " "tersedia jika\n" "   layanan key-manager diaktifkan dan Anda memiliki wewenang untuk " "mencantumkan daftar sertifikat dan\n" "   rahasia" msgid "The redirect url must be a valid http or https url." msgstr "URL pengalihan harus berupa http atau https url yang valid." msgid "" "The target of the health check HTTP request to the member. Must be a valid " "URL path." msgstr "" "Target pemeriksaan kesehatan meminta HTTP ke member. Harus berupa jalur URL " "yang valid." msgid "" "The time after which a health check times out. Must be a number greater than " "or equal to 0\n" " and less than or equal to the interval." msgstr "" "Waktu setelah waktu pemeriksaan kesehatan habis. Harus angka lebih besar " "dari atau sama dengan 0\n" "   dan kurang dari atau sama dengan interval." msgid "The timeout must be a number between 0 and 31536000000." msgstr "Batas waktu harus berupa angka antara 0 dan 31536000000." msgid "The timeout must be a number greater than or equal to 0." msgstr "Timeout harus berupa angka yang lebih besar dari atau sama dengan 0." msgid "" "The type of session persistence for distributing traffic to the pool members." msgstr "" "Jenis sesi persistensi untuk mendistribusikan lalu lintas ke anggota kolam " "renang." msgid "" "The value to use for the comparison. For example, the file type to compare." msgstr "" "The value yang akan digunakan untuk perbandingan. Misalnya, jenis file (file " "type) untuk dibandingkan." msgid "" "Time, in milliseconds, to wait for additional TCP packets for content\n" " inspection. Default: 0." msgstr "" "Waktu, dalam milidetik, untuk menunggu paket TCP tambahan untuk konten\n" "   inspeksi. Default: 0." msgid "Timeout" msgstr "Timeout" msgid "Timeout (sec)" msgstr "Timeout (sec)" msgid "Timeout:" msgstr "Timeout (waktu habis):" msgid "Type" msgstr "Type" msgid "Type:" msgstr "Type:" msgid "URL Path" msgstr "URL Path" msgid "URL Path:" msgstr "URL Path:" msgid "Unable to create flavor profile." msgstr "Tidak dapat membuat profil flavor." msgid "Unable to create flavor." msgstr "Tidak dapat membuat flavor." msgid "Unable to create health monitor." msgstr "Tidak dapat membuat health monitor." msgid "Unable to create l7 policy." msgstr "Tidak dapat membuat kebijakan l7." msgid "Unable to create l7 rule." msgstr "Tidak dapat membuat aturan l7." msgid "Unable to create listener." msgstr "Tidak dapat membuat listener." msgid "Unable to create load balancer." msgstr "Tidak dapat membuat load balancer." msgid "Unable to create pool." msgstr "Tidak dapat membuat pool." #, python-format msgid "Unable to delete Health Monitor: %s." msgid_plural "Unable to delete Health Monitors: %s." msgstr[0] "Unable to delete Health Monitor: %s." #, python-format msgid "Unable to delete L7 Policy: %s." msgid_plural "Unable to delete L7 Policies: %s." msgstr[0] "Unable to delete L7 Policy: %s." #, python-format msgid "Unable to delete L7 Rule: %s." msgid_plural "Unable to delete L7 Rules: %s." msgstr[0] "Unable to delete L7 Rule: %s." #, python-format msgid "Unable to delete Listener: %s." msgid_plural "Unable to delete Listeners: %s." msgstr[0] "Unable to delete Listener: %s." #, python-format msgid "Unable to delete Load Balancer: %s." msgid_plural "Unable to delete Load Balancers: %s." msgstr[0] "Unable to delete Load Balancer: %s." #, python-format msgid "Unable to delete Member: %s." msgid_plural "Unable to delete Members: %s." msgstr[0] "Unable to delete Member: %s." #, python-format msgid "Unable to delete Pool: %s." msgid_plural "Unable to delete Pools: %s." msgstr[0] "Unable to delete Pool: %s." msgid "Unable to delete flavor profile." msgstr "Tidak dapat menghapus profil flavor." msgid "Unable to delete flavor." msgstr "Tidak dapat menghapus flavor." msgid "Unable to delete health monitor." msgstr "Tidak dapat menghapus health monitor." msgid "Unable to delete l7 policy." msgstr "Tidak dapat menghapus kebijakan l7." msgid "Unable to delete l7 rule." msgstr "Tidak dapat menghapus aturan l7." msgid "Unable to delete listener." msgstr "Tidak dapat menghapus listener." msgid "Unable to delete load balancer." msgstr "Tidak dapat menghapus load balancer." msgid "Unable to delete member." msgstr "Tidak dapat menghapus member." msgid "Unable to delete pool." msgstr "Tidak dapat menghapus pool." #, python-format msgid "Unable to disassociate floating IP address from load balancer: %s." msgstr "Tidak dapat memisahkan alamat IP mengambang dari load balancer: %s." msgid "Unable to retrieve SSL certificates." msgstr "Tidak dapat mengambil sertifikat SSL." msgid "Unable to retrieve flavor profile." msgstr "Tidak dapat mengambil profil flavor." msgid "Unable to retrieve flavor profiles." msgstr "Tidak dapat mengambil profil flavor." msgid "Unable to retrieve flavor." msgstr "Tidak dapat mengambil flavor." msgid "Unable to retrieve flavors." msgstr "Tidak dapat mengambil flavors." msgid "Unable to retrieve health monitor." msgstr "Tidak dapat mengambil health monitor." msgid "Unable to retrieve health monitors." msgstr "Tidak dapat mengambil health monitor." msgid "Unable to retrieve l7 policies." msgstr "Tidak dapat mengambil kebijakan l7." msgid "Unable to retrieve l7 policy." msgstr "Tidak dapat mengambil kebijakan l7." msgid "Unable to retrieve l7 rule." msgstr "Tidak dapat mengambil aturan l7." msgid "Unable to retrieve l7 rules." msgstr "Tidak dapat mengambil aturan l7." msgid "Unable to retrieve listener." msgstr "Tidak dapat mengambil listener." msgid "Unable to retrieve listeners." msgstr "Tidak dapat mengambil listener." msgid "Unable to retrieve load balancer." msgstr "Tidak dapat mengambil load balancer." msgid "Unable to retrieve load balancers." msgstr "Tidak dapat mengambil load balancer." msgid "Unable to retrieve member." msgstr "Tidak dapat mengambil member." msgid "Unable to retrieve members." msgstr "Tidak dapat mengambil member." msgid "Unable to retrieve pool." msgstr "Tidak dapat mengambil pool." msgid "Unable to retrieve pools." msgstr "Tidak dapat mengambil pool." msgid "Unable to retrieve secrets." msgstr "Tidak dapat mengambil rahasia." msgid "Unable to update flavor profile." msgstr "Tidak dapat memperbarui profil flavor." msgid "Unable to update flavor." msgstr "Tidak dapat memperbarui flavor." msgid "Unable to update health monitor." msgstr "Tidak dapat memperbarui health monitor." msgid "Unable to update l7 policy." msgstr "Tidak dapat memperbarui kebijakan l7." msgid "Unable to update l7 rule." msgstr "Tidak dapat memperbarui aturan l7." msgid "Unable to update listener." msgstr "Tidak dapat memperbarui listener." msgid "Unable to update load balancer." msgstr "Tidak dapat memperbarui load balancer." msgid "Unable to update member list." msgstr "Tidak dapat memperbarui member list." msgid "Unable to update member." msgstr "Tidak dapat memperbarui member." msgid "Unable to update pool." msgstr "Tidak dapat memperbarui pool." msgid "Update" msgstr "Update" msgid "Update Health Monitor" msgstr "Memperbarui Health Monitor" msgid "Update L7 Policy" msgstr "Perbarui Kebijakan L7" msgid "Update L7 Rule" msgstr "Perbarui Aturan L7" msgid "Update Listener" msgstr "Update Listener" msgid "Update Load Balancer" msgstr "Update Load Balancer" msgid "Update Member" msgstr "Update Member" msgid "Update Pool" msgstr "Update Pool" msgid "Updated At" msgstr "Updated At" msgid "" "Use the key-manager service to create any certificate containers before " "creating the listener.\n" " The following documentation provides information on how to create a " "certificate container:" msgstr "" "Gunakan layanan key-manager untuk membuat wadah sertifikat sebelum membuat " "listener.\n" "     Dokumentasi berikut memberikan informasi tentang cara membuat " "certificate container:" msgid "Value" msgstr "Value" msgid "Value:" msgstr "Value:" msgid "Weight" msgstr "Weight" msgid "Weight:" msgstr "Weight (bobot):" msgid "" "When true the logic of the rule is inverted. For example, with invert\n" " true, equal to would become not equal to." msgstr "" "Ketika benar logika aturan dibalik. Misalnya, dengan membalikkan benar, sama " "dengan menjadi tidak sama dengan." msgid "X-Forwarded-For" msgstr "X-Forwarded-For" msgid "X-Forwarded-Port" msgstr "X-Forwarded-Port" msgid "X-Forwarded-Proto" msgstr "X-Forwarded-Proto" msgid "Yes" msgstr "Yes" #, python-format msgid "" "You are about to disassociate the floating IP address from load balancer \"%s" "\". Please confirm." msgstr "" "Anda akan memutuskan kaitan alamat IP mengambang dari load balancer \"%s\". " "Tolong konfirmasi." #, python-format msgid "You have selected \"%s\". Deleted L7 Policy is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted L7 Policies are not recoverable." msgstr[0] "You have selected \"%s\". Deleted L7 Policy is not recoverable." #, python-format msgid "You have selected \"%s\". Deleted L7 Rule is not recoverable." msgid_plural "You have selected \"%s\". Deleted L7 Rules are not recoverable." msgstr[0] "You have selected \"%s\". Deleted L7 Rule is not recoverable." #, python-format msgid "You have selected \"%s\". Deleted health monitor is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted health monitors are not recoverable." msgstr[0] "" "You have selected \"%s\". Deleted health monitor is not recoverable." #, python-format msgid "You have selected \"%s\". Deleted listener is not recoverable." msgid_plural "You have selected \"%s\". Deleted listeners are not recoverable." msgstr[0] "You have selected \"%s\". Deleted listener is not recoverable." #, python-format msgid "" "You have selected \"%s\". Deleted load balancer is not recoverable and this " "deletion will delete all of the sub-resources." msgid_plural "" "You have selected \"%s\". Deleted load balancers are not recoverable and " "this deletion will delete all of the sub-resources." msgstr[0] "" "You have selected \"%s\". Deleted load balancer is not recoverable and this " "deletion will delete all of the sub-resources." #, python-format msgid "You have selected \"%s\". Deleted member is not recoverable." msgid_plural "You have selected \"%s\". Deleted members are not recoverable." msgstr[0] "You have selected \"%s\". Deleted member is not recoverable." #, python-format msgid "You have selected \"%s\". Deleted pool is not recoverable." msgid_plural "You have selected \"%s\". Deleted pools are not recoverable." msgstr[0] "You have selected \"%s\". Deleted pool is not recoverable." ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.453101 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ja/0000775000175100017510000000000015033037476022500 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ja/LC_MESSAGES/0000775000175100017510000000000015033037476024265 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ja/LC_MESSAGES/django.po0000664000175100017510000000114115033037474026062 0ustar00mylesmyles# Akihiro Motoki , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2018-01-25 04:23+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-01-24 06:35+0000\n" "Last-Translator: Akihiro Motoki \n" "Language-Team: Japanese\n" "Language: ja\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "Load Balancers" msgstr "ロードバランサー" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ja/LC_MESSAGES/djangojs.po0000664000175100017510000013120215033037474026421 0ustar00mylesmyles# Akihiro Motoki , 2018. #zanata # Yuko Katabami , 2018. #zanata # Takashi Kuroda , 2019. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2022-08-16 20:34+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2019-03-20 05:35+0000\n" "Last-Translator: Takashi Kuroda \n" "Language-Team: Japanese\n" "Language: ja\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" #, python-format msgid "%(ip)s..." msgstr "%(ip)s..." msgid "A new health monitor is being created." msgstr "新しいヘルスモニターは作成中です。" msgid "A new l7 policy is being created." msgstr "新しい L7 ポリシーは作成中です。" msgid "A new listener is being created." msgstr "新しいリスナーは作成中です。" msgid "A new load balancer is being created." msgstr "新しいロードバランサーは作成中です。" msgid "A new pool is being created." msgstr "新しいプールは作成中です。" msgid "" "A pool represents a group of members over which the load balancing will be " "applied." msgstr "プールは負荷分散が適用されるメンバーのグループを表します。" msgid "APP_COOKIE: Session persistence based on application cookie." msgstr "" "アプリケーションクッキー: アプリケーションクッキーに基づくセッション永続性" msgid "Action" msgstr "アクション" msgid "Action:" msgstr "アクション:" msgid "Active" msgstr "稼働中" msgid "Add" msgstr "追加" msgid "Add external member" msgstr "メンバーの追加" msgid "Add members to the load balancer pool." msgstr "ロードバランサーにメンバーを追加します。" msgid "Add/Remove Members" msgstr "メンバーの追加/削除" msgid "Add/Remove Pool Members" msgstr "プールメンバーの追加・削除" msgid "" "Additional headers insertion into HTTP header,\n" " only \"X-Forwarded-For\", \"X-Forwarded-Port\" and \"X-Forwarded-Proto\" " "are supported." msgstr "" "HTTP ヘッダーへの追加ヘッダー挿入で、\n" "\"X-Forwarded-For\"、\"X-Forwarded-Port\"、および \"X-Forwarded-Proto\" のみ" "がサポートされています。" msgid "Admin State Up" msgstr "管理状態有効" msgid "Algorithm" msgstr "アルゴリズム" msgid "Algorithm:" msgstr "アルゴリズム:" msgid "Allocated Members" msgstr "割り当て済みのメンバー" msgid "" "An L7 Policy is a collection of L7 rules associated with a Listener, and " "which may also have an association to a back-end pool" msgstr "" "L7 ポリシーは、リスナーに関連付けられた L7 ルールのコレクションで、バックエン" "ドプールに関連付けられている場合もあります。" msgid "" "An L7 Rule is a single, simple logical test which returns either true or\n" "false." msgstr "" "L7 ルールは、単一の簡単な論理テストで、\n" "true または false が返されます。" msgid "" "An alternate IP address used for health monitoring a backend member.\n" " Default is null which monitors the member address." msgstr "" "バックエンドメンバーのヘルスモニタリングに使用する代替の IP アドレス。\n" "デフォルトは null で、メンバーのアドレスをモニターします。" msgid "" "An alternate protocol port used for health monitoring a backend member.\n" " Default is null which monitors the member protocol port." msgstr "" "バックエンドメンバーのヘルスモニタリングに使用する代替のプロトコルポート。\n" "デフォルトは null で、メンバーのプロトコルポートをモニターします。" msgid "An error occurred. Please try again later." msgstr "エラーが発生しました。後からもう一度お試しください。" msgid "Associate" msgstr "割り当て" msgid "Associate Floating IP" msgstr "Floating IP の割り当て" msgid "Associate Floating IP Address" msgstr "Floating IP アドレス の割り当て" msgid "Associating floating IP with load balancer." msgstr "ロードバランサーの Floating IP アドレスの割り当て" msgid "Available Instances" msgstr "有効なインスタンス" msgid "Backend member connection timeout in milliseconds. Default: 5000." msgstr "バックエンドメンバーの接続タイムアウト (ミリ秒)。デフォルト: 5000" msgid "Backend member inactivity timeout in milliseconds. Default: 50000." msgstr "" "バックエンドメンバーの非アクティブタイムアウト (ミリ秒)。デフォルト: 50000" msgid "Backup" msgstr "バックアップ" msgid "Backup:" msgstr "バックアップ:" msgid "CIDR" msgstr "CIDR" msgid "CONTAINS: String contains." msgstr "CONTAINS: 文字列を含む" msgid "" "COOKIE: The rule looks for a cookie named by the key parameter and\n" " compares it against the value parameter in the rule." msgstr "" "クッキー: ルールは、key パラメーターで命名されたクッキーを探して、\n" " ルール内の value パラメーターと比較します。" msgid "Cancel" msgstr "取り消し" msgid "Certificate Name" msgstr "証明書名" msgid "Client Data Timeout" msgstr "クライアントデータタイムアウト" msgid "Client Data Timeout:" msgstr "クライアントデータタイムアウト:" msgid "Compare Type" msgstr "比較の種別" msgid "Compare Type:" msgstr "比較の種別:" msgid "Confirm Delete Health Monitor" msgid_plural "Confirm Delete Health Monitors" msgstr[0] "ヘルスモニターの削除の確認" msgid "Confirm Delete L7 Policy" msgid_plural "Confirm Delete L7 Policies" msgstr[0] "L7 ポリシーの削除の確認" msgid "Confirm Delete L7 Rule" msgid_plural "Confirm Delete L7 Rules" msgstr[0] "L7 ルールの削除の確認" msgid "Confirm Delete Listener" msgid_plural "Confirm Delete Listeners" msgstr[0] "リスナーの削除の確認" msgid "Confirm Delete Load Balancer" msgid_plural "Confirm Delete Load Balancers" msgstr[0] "ロードバランサーの削除の確認" msgid "Confirm Delete Member" msgid_plural "Confirm Delete Members" msgstr[0] "メンバーの削除の確認" msgid "Confirm Delete Pool" msgid_plural "Confirm Delete Pools" msgstr[0] "プールの削除の確認" msgid "Confirm Disassociate Floating IP Address" msgstr "Floating IP アドレスの割り当て解除の確認" msgid "Connection Limit" msgstr "最大接続数" msgid "Connection Limit:" msgstr "最大接続数:" msgid "Contains" msgstr "含む" msgid "Cookie" msgstr "クッキー" msgid "Cookie Name" msgstr "クッキー名" msgid "Create Health Monitor" msgstr "ヘルスモニターの作成" msgid "Create L7 Policy" msgstr "L7 ポリシーの作成" msgid "Create L7 Rule" msgstr "L7 ルールの作成" msgid "Create Listener" msgstr "リスナーの作成" msgid "Create Load Balancer" msgstr "ロードバランサーの作成" msgid "Create Pool" msgstr "プールの作成" msgid "Created At" msgstr "作成時刻" msgid "Default Pool ID" msgstr "デフォルトプール ID" msgid "Default Pool ID:" msgstr "デフォルトプール ID:" msgid "Default TLS Container Ref" msgstr "デフォルトの TLS コンテナー参照" msgid "Degraded" msgstr "縮退中" msgid "Delay" msgstr "遅延" msgid "Delay (sec)" msgstr "遅延 (秒)" msgid "Delay:" msgstr "遅延:" msgid "Delete Health Monitor" msgid_plural "Delete Health Monitors" msgstr[0] "ヘルスモニターの削除" msgid "Delete Health Monitors" msgstr "ヘルスモニターの削除" msgid "Delete L7 Policies" msgstr "L7 ポリシーの削除" msgid "Delete L7 Policy" msgid_plural "Delete L7 Policies" msgstr[0] "L7 ポリシーの削除" msgid "Delete L7 Rule" msgid_plural "Delete L7 Rules" msgstr[0] "L7 ルールの削除" msgid "Delete L7 Rules" msgstr "L7 ルールの削除" msgid "Delete Listener" msgid_plural "Delete Listeners" msgstr[0] "リスナーの削除" msgid "Delete Listeners" msgstr "リスナーの削除" msgid "Delete Load Balancer" msgid_plural "Delete Load Balancers" msgstr[0] "ロードバランサーの削除" msgid "Delete Load Balancers" msgstr "ロードバランサーの削除" msgid "Delete Member" msgid_plural "Delete Members" msgstr[0] "メンバーの削除" msgid "Delete Members" msgstr "メンバーの削除" msgid "Delete Pool" msgid_plural "Delete Pools" msgstr[0] "プールの削除" msgid "Delete Pools" msgstr "プールの削除" #, python-format msgid "Deleted Health Monitor: %s." msgid_plural "Deleted Health Monitors: %s." msgstr[0] "ヘルスモニター %s を削除しました。" #, python-format msgid "Deleted L7 Policy: %s." msgid_plural "Deleted L7 Policies: %s." msgstr[0] "L7 ポリシー %s を削除しました。" #, python-format msgid "Deleted L7 Rule: %s." msgid_plural "Deleted L7 Rules: %s." msgstr[0] "L7 ルール %s を削除しました。" #, python-format msgid "Deleted Listener: %s." msgid_plural "Deleted Listeners: %s." msgstr[0] "リスナー %s を削除しました。" #, python-format msgid "Deleted Load Balancer: %s." msgid_plural "Deleted Load Balancers: %s." msgstr[0] "ロードバランサー %s を削除しました。" #, python-format msgid "Deleted Member: %s." msgid_plural "Deleted Members: %s." msgstr[0] "メンバー %s を削除しました。" #, python-format msgid "Deleted Pool: %s." msgid_plural "Deleted Pools: %s." msgstr[0] "プール %s を削除しました。" msgid "Description" msgstr "説明" msgid "Disassociate" msgstr "割り当て解除" msgid "Disassociate Floating IP" msgstr "Floating IP の割り当て解除" #, python-format msgid "Disassociated floating IP address from load balancer: %s." msgstr "" "ロードバランサー %s から Floating IP アドレスの割り当てを解除しました。" msgid "ENDS_WITH: String ends with." msgstr "ENDS_WITH: 文字列で終わる" msgid "EQUAL_TO: String is equal to." msgstr "EQUAL_TO: 文字列に等しい" msgid "" "Each port that listens for traffic on a particular load balancer is " "configured separately and\n" " tied to the load balancer. Multiple listeners can be associated with the " "same load balancer but\n" " each must use a unique port." msgstr "" "あるロードバランサーでトラフィックをリッスンするポート番号は、個別に設定し" "て、ロードバランサーに関連付けできます。\n" " 同じロードバランサーに複数のリスナーを関連付けできますが、\n" " それぞれが一意のポートを使用しなければいけません。" msgid "Edit Health Monitor" msgstr "ヘルスモニターの編集" msgid "Edit L7 Policy" msgstr "L7 ポリシーの編集" msgid "Edit L7 Rule" msgstr "L7 ルールの編集" msgid "Edit Listener" msgstr "リスナーの編集" msgid "Edit Load Balancer" msgstr "ロードバランサーを編集" msgid "Edit Member" msgstr "メンバーの編集" msgid "Edit Pool" msgstr "プールの編集" msgid "Ends With" msgstr "終了" msgid "Equal To" msgstr "等しい" msgid "Error" msgstr "エラー" msgid "Expected Codes" msgstr "コードの期待値" msgid "Expected Codes:" msgstr "コードの期待値:" msgid "Expiration Date" msgstr "有効期限" msgid "" "FILE_TYPE: The rule compares the last portion of the URI against\n" " the value parameter in the rule. (eg. \"txt\", \"jpg\", etc.)" msgstr "" "ファイルタイプ: ルールは URI の最後の部分を\n" " ルール内の value パラメーター (例: \"txt\"、\"jpg\" など) と比較しま" "す。" msgid "File Type" msgstr "ファイルタイプ" msgid "Flavor" msgstr "フレーバー" msgid "Flavor Description" msgstr "フレーバーの説明" msgid "Flavor ID" msgstr "フレーバー ID" msgid "Floating IP" msgstr "Floating IP" msgid "Floating IP address or pool" msgstr "Floating IP アドレスまたはプール" msgid "Floating IP addresses" msgstr "Floating IP アドレス" msgid "Floating IP pools" msgstr "Floating IP プール" msgid "Frontend client inactivity timeout in milliseconds. Default: 50000." msgstr "" "フロントエンドクライアントの非アクティブタイムアウト (ミリ秒)。デフォルト: " "50000" msgid "" "HEADER: The rule looks for a header defined in the key parameter\n" " and compares it against the value parameter in the rule." msgstr "" "ヘッダー: ルールは、key パラメーターで定義されたヘッダーを探して、\n" " ルール内の value パラメーターと比較します。" msgid "" "HOST_NAME: The rule does a comparison between the HTTP/1.1\n" " hostname in the request against the value parameter in the rule." msgstr "" "ホスト名: ルールはリクエスト内の HTTP/1.1 ホスト名を\n" " ルール内の value パラメーターと比較します。" msgid "HTTP Method" msgstr "HTTP メソッド" msgid "HTTP Method:" msgstr "HTTP メソッド:" msgid "HTTP_COOKIE: Session persistence based on http cookie." msgstr "http クッキー: http クッキーに基づくセッション永続性" msgid "Header" msgstr "ヘッダー" msgid "Health Monitor" msgstr "ヘルスモニター" msgid "Health Monitor ID" msgstr "ヘルスモニター ID" msgid "Health Monitors" msgstr "ヘルスモニター" msgid "Host Name" msgstr "ホスト名" msgid "ID" msgstr "ID" msgid "IP Address" msgstr "IP アドレス" #, python-format msgid "IP Addresses (%(count)s)" msgstr "IP アドレス (%(count)s)" msgid "IP address" msgstr "IP アドレス" msgid "IP address:" msgstr "IP アドレス:" msgid "" "If an IP address is provided it must be a well-formed IPv4 or IPv6 address. " "The system will\n" " attempt to assign the provided IP address to the load balancer. If an IP " "address is not provided\n" " then one will be allocated for you." msgstr "" "IP アドレスを指定する場合には、正しい形式の IPv4 または IPv6 アドレスを使用す" "る必要があります。\n" " システムは、指定された IP アドレスをロードバランサーに割り当てるように試み" "ます。IP アドレスが指定されていない場合には、\n" " システムによって確保されます。" msgid "" "If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL " "certificates must\n" " be selected. The first certificate will be the default." msgstr "" "リスナーが TERMINATED_HTTPS プロトコルを使用する場合には、SSL 証明書を1 つま" "たは複数選択する必要があります。\n" " 最初の証明書がデフォルトとなります。" msgid "Inactive" msgstr "非稼働" msgid "Insert Headers" msgstr "ヘッダーの挿入" msgid "Insert Headers:" msgstr "ヘッダーの挿入:" msgid "Invert" msgstr "反転" msgid "Invert:" msgstr "反転:" msgid "" "Is the member a backup? Backup members only receive traffic when all\n" " non-backup members are down." msgstr "" "メンバーがバックアップかどうか。バックアップメンバーは、すべての非バックアッ" "プメンバーが\n" "ダウンしている場合にのみトラフィックを受信します。" msgid "Key" msgstr "キー" msgid "Key Manager API Guide: Creating a Certificate Container" msgstr "Key Manager API ガイド: 証明書コンテナーの作成" msgid "Key Manager Service Command-Line Client" msgstr "Key Manager サービスのコマンドラインクライアント (CLI)" msgid "Key:" msgstr "キー:" msgid "L7 Policies" msgstr "L7 ポリシー" msgid "L7 Policy" msgstr "L7 ポリシー" msgid "L7 Policy Details" msgstr "L7 ポリシーの詳細" msgid "L7 Rule" msgstr "L7 ルール" msgid "L7 Rule Details" msgstr "L7 ルールの詳細" msgid "L7 Rules" msgstr "L7 ルール" msgid "" "LEAST_CONNECTIONS: Allocates requests to the instance with the least number " "of active\n" " connections." msgstr "" "最小接続数: アクティブな接続数が最も少ないメンバーにリクエストを割り当てま" "す。" msgid "Least Connections" msgstr "最小接続数" msgid "Listener" msgstr "リスナー" msgid "Listener Details" msgstr "リスナーの詳細" msgid "Listener ID" msgstr "リスナー ID" msgid "Listeners" msgstr "リスナー" msgid "Load Balancer" msgstr "ロードバランサー" msgid "Load Balancer Details" msgstr "ロードバランサーの詳細" msgid "Load Balancers" msgstr "ロードバランサー" msgid "Loading" msgstr "読み込み中" msgid "Max Retries" msgstr "最大試行回数" msgid "Max Retries Down" msgstr "ダウン時最大試行回数" msgid "Max Retries Down:" msgstr "ダウン時最大試行回数:" msgid "Max Retries:" msgstr "最大試行回数:" msgid "Member" msgstr "メンバー" msgid "Member Connect Timeout" msgstr "メンバー接続タイムアウト" msgid "Member Connect Timeout:" msgstr "メンバー接続タイムアウト:" msgid "Member Data Timeout" msgstr "メンバーデータタイムアウト" msgid "Member Data Timeout:" msgstr "メンバーデータタイムアウト:" msgid "Members" msgstr "メンバー" msgid "" "Members are the actual IP addresses that will receive traffic from the load " "balancer. Each\n" " member must have a unique combination of IP address and port." msgstr "" "メンバーは、ロードバランサーからのトラフィックを受信する実際の IP アドレスで" "す。\n" "メンバーには、IP アドレスとポートの一意の組み合わせが必要です。" msgid "Monitor Address" msgstr "モニターアドレス" msgid "Monitor Address:" msgstr "モニターアドレス:" msgid "Monitor Details" msgstr "モニターの詳細" msgid "Monitor Port" msgstr "モニターポート" msgid "Monitor Port:" msgstr "モニターポート:" msgid "Name" msgstr "名前" msgid "Network" msgstr "ネットワーク" msgid "Network ID" msgstr "ネットワーク ID" msgid "No" msgstr "いいえ" msgid "No Monitor" msgstr "モニターなし" msgid "No available certificates" msgstr "利用可能な証明書がありません" msgid "No available instances" msgstr "有効なインスタンスがありません" msgid "No items to display." msgstr "表示する項目がありません" msgid "No matching options" msgstr "一致するオプションはありません" msgid "No members have been allocated" msgstr "メンバーが割り当てられていません。" msgid "None" msgstr "なし" msgid "Offline" msgstr "オフライン" msgid "Online" msgstr "オンライン" msgid "Operating Status" msgstr "作動状態" msgid "Overview" msgstr "概要" msgid "" "PATH: The rule compares the path portion of the HTTP URI against\n" " the value parameter in the rule." msgstr "" "パス: ルールは HTTP URI のパスの部分を\n" " ルール内の value パラメーターと比較します。" msgid "Path" msgstr "パス" msgid "Pending Create" msgstr "作成待ち" msgid "Pending Delete" msgstr "削除待ち" msgid "Pending Update" msgstr "更新待ち" msgid "Please Wait" msgstr "お待ちください" msgid "Pool" msgstr "プール" msgid "Pool Details" msgstr "プールの詳細" msgid "Pool Members" msgstr "プールメンバー" msgid "Pool member has been updated." msgstr "プールメンバーが更新されました。" msgid "Pools" msgstr "プール" msgid "Port" msgstr "ポート" msgid "Port ID" msgstr "ポート ID" msgid "Port:" msgstr "ポート:" msgid "Position" msgstr "位置" msgid "Position:" msgstr "位置:" msgid "Project" msgstr "プロジェクト" msgid "Project ID" msgstr "プロジェクト ID" msgid "Protocol" msgstr "プロトコル" msgid "Protocol Port" msgstr "ポート番号" msgid "Protocol:" msgstr "プロトコル:" msgid "Provide the details for the health monitor." msgstr "ヘルスモニターの詳細を設定してください。" msgid "Provide the details for the l7 policy." msgstr "L7 ポリシーの詳細を設定してください。" msgid "Provide the details for the l7 rule." msgstr "L7 ルールの詳細を設定してください。" msgid "Provide the details for the listener." msgstr "リスナーの詳細を設定してください。" msgid "Provide the details for the load balancer." msgstr "ロードバランサーの詳細を設定してください。" msgid "Provide the details for the member." msgstr "メンバーの詳細を設定してください。" msgid "Provide the details for the pool." msgstr "プールの詳細を設定してください。" msgid "Provider" msgstr "プロバイダー" msgid "Provisioning Status" msgstr "プロビジョニング状態" msgid "" "REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated " "with the L7 policy." msgstr "" "プールにリダイレクト: L7 ポリシーに関連付けられたバックエンドに要求が転送され" "ます。" msgid "" "REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in " "the redirect_url parameter." msgstr "" "URL にリダイレクト: リクエストは、redirect_url パラメーターで定義されている " "URL に HTTP リダイレクトされるように送信されます。" msgid "REGEX: Perl type regular expression matching." msgstr "REGEX: Perl タイプの正規表現マッチ" msgid "" "REJECT: The request is denied with an appropriate response code, and not " "forwarded on to any back-end pool." msgstr "" "拒否: リクエストは、適切な応答コードで拒否され、どのバックエンドプールにも転" "送されません。" msgid "ROUND_ROBIN: Rotates requests evenly between multiple instances." msgstr "ラウンドロビン: リクエストを複数のメンバーで順番に均等に割り当てます。" msgid "Redirect Pool ID" msgstr "リダイレクト先プール ID" msgid "Redirect Pool ID:" msgstr "リダイレクト先プール ID" msgid "Redirect URL" msgstr "リダイレクト先 URL" msgid "Redirect URL:" msgstr "リダイレクト先 URL:" msgid "Redirect to Pool" msgstr "プールにリダイレクト" msgid "Redirect to URL" msgstr "URL にリダイレクト" msgid "Regex" msgstr "正規表現" msgid "Reject" msgstr "拒否" msgid "Remove" msgstr "削除" msgid "" "Requests matching this policy will be redirected to the pool with this ID. " "Only valid if action is REDIRECT_TO_POOL." msgstr "" "このポリシーに適合する要求は、この ID のプールにリダイレクトされます。アク" "ションが REDIRECT_TO_POOL (プールにリダイレクト) に指定されている場合にのみ有" "効です。" msgid "" "Requests matching this policy will be redirected to this URL. Only valid if " "action is REDIRECT_TO_URL." msgstr "" "このポリシーに適合する要求は、この URL にリダイレクトされます。アクションが " "REDIRECT_TO_URL (URL にリダイレクト) に指定されている場合にのみ有効です。" msgid "Round Robin" msgstr "ラウンドロビン" msgid "Rules" msgstr "ルール" msgid "SNI Container Refs" msgstr "SNI コンテナー参照" msgid "" "SOURCE_IP: Requests from a unique source IP address are consistently " "directed to the same instance." msgstr "" "送信元 IP: 同じ送信元 IP アドレスからのリクエストは同じメンバーに転送されま" "す。" msgid "SOURCE_IP: Session persistence based on source ip." msgstr "送信元 IP: 送信元 IP に基づくセッション永続性" msgid "SSL Certificates" msgstr "SSL 証明書" msgid "STARTS_WITH: String starts with." msgstr "STARTS_WITH: 文字列で始まる" msgid "" "Select a floating IP address to associate with the load balancer or a " "floating IP pool in which to allocate a new floating IP address." msgstr "" "ロードバランサを設定するためにフローティング IP アドレス、もしくは、新しいフ" "ローティング IP アドレス配置するためのフローティング IP アドレスプールを選択" "してください" msgid "Select certificates from the available certificates below" msgstr "以下の一覧から証明書を選択してください" msgid "Select one or more SSL certificates for the listener." msgstr "SSL 証明書を 1 つ以上選択してください" msgid "Session Persistence" msgstr "セッション永続性" msgid "Session Persistence:" msgstr "セッション永続性:" msgid "Source IP" msgstr "送信元 IP" msgid "Starts With" msgstr "開始" msgid "Subnet" msgstr "サブネット" msgid "Subnet ID" msgstr "サブネット ID" msgid "Subnet:" msgstr "サブネット:" msgid "TCP Inspect Timeout" msgstr "TCP 検査タイムアウト" msgid "TCP Inspect Timeout:" msgstr "TCP 検査タイムアウト:" msgid "" "The Available Instances table contains existing compute instances that can " "be added as members\n" " of the pool. Use the \"Add external member\" button to add a member not " "found in the Available\n" " Instances table." msgstr "" "利用可能なインスタンスの表には、プールのメンバーとして追加可能な既存のコン" "ピュートインスタンスが含まれます。\n" " 利用可能なインスタンスの表にないメンバーを追加するには、\n" " 「メンバーの追加」ボタンを使用します。" msgid "The HTTP method used to perform the health check." msgstr "ヘルスチェックの実行に使用される HTTP メソッドです。" msgid "The ID of the pool used by the listener if no L7 policies match." msgstr "一致する L7 ポリシーがない場合にリスナーが使用するプールの ID" msgid "The IP address is not valid." msgstr "IP アドレスが無効です。" msgid "" "The IP address of the member to receive traffic from the load balancer. Must " "be a well-formed\n" " IPv4 or IPv6 address." msgstr "" "ロードバランサーからトラフィックを受信するメンバーの IP アドレス。\n" " 正しい形式の IPv4 または IPv6 アドレスでなければいけません。" msgid "" "The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL." msgstr "" "L7 ポリシーのアクション、拒否、URL にリダイレクト、プールにリダイレクトのいず" "れかです。" msgid "The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH." msgstr "" "L7 ルールのタイプ。クッキー、ファイルタイプ、ヘッダー、ホスト名、パスのいずれ" "か 1 つです。" msgid "The URL path is not valid." msgstr "URL は有効ではありません。" msgid "" "The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, or STARTS_WITH." msgstr "" "L7 ルールの比較タイプ。含む、終了、等しい、正規表現、\n" "または開始のいずれか 1 つです。" msgid "The connection limit must be a number greater than or equal to -1." msgstr "最大接続数は -1 以上の数字でなければいけません。" msgid "" "The expected HTTP status codes to get from a successful health check. Must " "be a single number,\n" " a comma separated list of numbers, or a range (two numbers separated by a " "hyphen)." msgstr "" "ヘルスチェックが成功した場合の HTTP ステータスコードの期待値。\n" " 単一の値、複数の値のコンマ区切りリスト、範囲 (ハイフンで区切られた 2 つの" "値) のいずれかにする必要があります。" msgid "The expected status code is not valid." msgstr "ステータスコードの期待値が有効ではありません。" msgid "The health check interval must be greater than or equal to the timeout." msgstr "ヘルスチェックの間隔はタイムアウト値以上でなければいけません。" msgid "The health monitor has been updated." msgstr "ヘルスモニターが更新されました。" msgid "" "The health monitor is used to determine the health of your pool members. " "Health checks\n" " routinely run against each member within the pool and the result of the " "health check is used\n" " to determine if the member receives new connections. Each pool can only " "have one health\n" " monitor." msgstr "" "ヘルスモニターは、プールメンバーの正常性の確認に使用されます。\n" " ヘルスチェックは、プール内の各メンバーに対して定期的に実行され、ヘルス" "チェックの結果は、\n" " そのメンバーが新規接続を受けるかどうかの決定に使用されます。\n" " 1 つのプールで使用できるヘルスモニターは 1 つのみです。" msgid "" "The interval between health checks. Must be greater than or equal to the " "timeout." msgstr "ヘルスチェックの間隔はタイムアウト値以上でなければいけません。" msgid "" "The key to use for the comparison. For example, the name of the cookie\n" " to evaluate." msgstr "" "比較に使用するキー。\n" " 例: 評価するクッキーの名前" msgid "The l7policy has been updated." msgstr "L7 ポリシーが更新されました。" msgid "The l7rule has been updated." msgstr "L7 ルールが更新されました。" msgid "The listener has been updated." msgstr "リスナーが更新されました。" msgid "" "The load balancer algorithm that distributes traffic to the pool members." msgstr "トラフィックをプールメンバーに分配するロードバランサーのアルゴリズム。" msgid "The load balancer has been updated." msgstr "ロードバランサーが更新されました。" msgid "" "The load balancer occupies a neutron network port and has an IP address " "assigned from a subnet." msgstr "" "ロードバランサーは neutron のネットワークポートを所有し、サブネットから割り当" "てられた IP アドレスを持ちます。" msgid "The max retry count must be a number between 1 and 10." msgstr "最大試行回数は 1~10 までとなっています。" msgid "The max retry down count must be a number between 1 and 10." msgstr "ダウン時最大試行回数は 1 - 10 の数字でなければいけません。" msgid "" "The maximum number of connections permitted for this listener.\n" " Default value is -1 which represents infinite connections." msgstr "" "このリスナーで許可する最大接続数。\n" " デフォルト値は -1 で、無制限の接続を表します。" msgid "The monitor address must be a valid IP address." msgstr "モニターアドレスは有効な IP アドレスでなければいけません。" msgid "The monitor port must be a number between 1 and 65535." msgstr "モニターポートは 1 〜 256 の数字でなければいけません。" msgid "The network on which to allocate the load balancer's IP address." msgstr "ロードバランサーの IP アドレスを割り当てるネットワーク" msgid "The network which contains the IP address of the member." msgstr "メンバーの IP アドレスを含むネットワーク。" msgid "" "The number of allowed connection failures before marking the member as " "error. Must be a\n" " number from 1 to 10. The default is 3." msgstr "" "メンバーがエラーと識別されるまで許容可能な接続失敗回数。1 から 10 までの\n" "数字でなければいけません。デフォルトは 3 です。" msgid "" "The number of allowed connection failures before marking the member as " "inactive. Must be a\n" " number from 1 to 10." msgstr "" "メンバーが無効になるまで許容可能な接続エラー回数。\n" " 1 から 10 までの数字でなければいけません。" msgid "The pool has been updated." msgstr "プールが更新されました。" msgid "The pool members have been updated." msgstr "プールメンバーが更新されました。" msgid "The port must be a number between 1 and 65535." msgstr "ポートは 1 ~ 65535 の数字でなければいけません。" msgid "" "The port must be unique among all listeners attached to this load balancer." msgstr "" "ポートは、このロードバランサーにアタッチされた全リスナーの間で、一意でなけれ" "ばいけません。" msgid "" "The port on which the front end listens. Must be an integer from 1 to 65535." msgstr "" "フロントエンドがリッスンするポート。1 から 65535 までの整数でなければいけませ" "ん。" msgid "" "The port on which the member listens for traffic. Must be a number from 1 to " "65535." msgstr "" "メンバーがトラフィックをリッスンするポート。1 から 65535 までの数字でなければ" "いけません。" msgid "The position must be a number between 1 and 2147483647." msgstr "位置は 1 〜 2147483647 の数字でなければいけません。" msgid "The position of this policy on the listener. Positions start at 1." msgstr "リスナー上でのこのポリシーの位置。位置は 1 から開始します。" msgid "" "The protocol for which the front end listens. The TERMINATED_HTTPS protocol " "is only available if\n" " the key-manager service is enabled and you have authority to list " "certificate containers and\n" " secrets." msgstr "" "フロントエンドがリッスンするプロトコル。TERMINATED_HTTPS プロトコルは、key-" "manager サービスが有効化されており、\n" " 証明書のコンテナーとシークレットを一覧表示する権限がある場合にのみ\n" " 利用可能です。" msgid "The redirect url must be a valid http or https url." msgstr "" "リダイレクト先 URL は有効な http または https の URL でなければいけません。" msgid "" "The target of the health check HTTP request to the member. Must be a valid " "URL path." msgstr "" "メンバーに対するヘルスチェックの HTTP リクエストのターゲット。有効な URL パス" "でなければいけません。" msgid "" "The time after which a health check times out. Must be a number greater than " "or equal to 0\n" " and less than or equal to the interval." msgstr "" "ヘルスチェックがタイムアウトになる時間。\n" " 0 以上の数字でなければいけません。" msgid "The timeout must be a number between 0 and 31536000000." msgstr "タイムアウトは 0 〜 31536000000 の数字でなければいけません。" msgid "The timeout must be a number greater than or equal to 0." msgstr "タイムアウトの値 は 0 以上でなければなりません。" msgid "" "The type of session persistence for distributing traffic to the pool members." msgstr "トラフィックをプールメンバーに分配する際のセッション永続性の種別。" msgid "" "The value to use for the comparison. For example, the file type to compare." msgstr "比較に使用する値。例: 比較するファイルタイプ" msgid "" "Time, in milliseconds, to wait for additional TCP packets for content\n" " inspection. Default: 0." msgstr "" "コンテンツの検査に向けて追加の TCP パケットを待つ時間 (ミリ秒)。\n" " デフォルト: 0" msgid "Timeout" msgstr "タイムアウト" msgid "Timeout (sec)" msgstr "タイムアウト (秒)" msgid "Timeout:" msgstr "タイムアウト:" msgid "Type" msgstr "種別" msgid "Type:" msgstr "種別:" msgid "URL Path" msgstr "URL パス" msgid "URL Path:" msgstr "URL パス:" msgid "Unable to create flavor profile." msgstr "フレーバーのプロファイルを作成できません。" msgid "Unable to create flavor." msgstr "フレーバーを作成できません。" msgid "Unable to create health monitor." msgstr "ヘルスモニターを作成できません。" msgid "Unable to create l7 policy." msgstr "L7 ポリシーを作成できません。" msgid "Unable to create l7 rule." msgstr "L7 ルールを作成できません。" msgid "Unable to create listener." msgstr "リスナーを作成できません。" msgid "Unable to create load balancer." msgstr "ロードバランサーを作成できません。" msgid "Unable to create pool." msgstr "プールを作成できません。" #, python-format msgid "Unable to delete Health Monitor: %s." msgid_plural "Unable to delete Health Monitors: %s." msgstr[0] "ヘルスモニターを削除できません: %s" #, python-format msgid "Unable to delete L7 Policy: %s." msgid_plural "Unable to delete L7 Policies: %s." msgstr[0] "L7 ポリシーを削除できません: %s" #, python-format msgid "Unable to delete L7 Rule: %s." msgid_plural "Unable to delete L7 Rules: %s." msgstr[0] "L7 ルールを削除できません: %s" #, python-format msgid "Unable to delete Listener: %s." msgid_plural "Unable to delete Listeners: %s." msgstr[0] "リスナーを削除できません: %s" #, python-format msgid "Unable to delete Load Balancer: %s." msgid_plural "Unable to delete Load Balancers: %s." msgstr[0] "ロードバランサーを削除できません: %s" #, python-format msgid "Unable to delete Member: %s." msgid_plural "Unable to delete Members: %s." msgstr[0] "メンバーを削除できません: %s" #, python-format msgid "Unable to delete Pool: %s." msgid_plural "Unable to delete Pools: %s." msgstr[0] "プールを削除できません: %s" msgid "Unable to delete flavor profile." msgstr "フレーバーのプロファイルを削除できません。" msgid "Unable to delete flavor." msgstr "フレーバーを削除できません。" msgid "Unable to delete health monitor." msgstr "ヘルスモニターを削除できません。" msgid "Unable to delete l7 policy." msgstr "L7 ポリシーを削除できません。" msgid "Unable to delete l7 rule." msgstr "L7 ルールを削除できません。" msgid "Unable to delete listener." msgstr "リスナーを削除できません。" msgid "Unable to delete load balancer." msgstr "ロードバランサーを削除できません。" msgid "Unable to delete member." msgstr "メンバーを削除できません。" msgid "Unable to delete pool." msgstr "プールを削除できません。" #, python-format msgid "Unable to disassociate floating IP address from load balancer: %s." msgstr "" "ロードバランサー %s から Floating IP アドレスの割り当て解除ができません。" msgid "Unable to retrieve SSL certificates." msgstr "SSL 証明書を取得できません。" msgid "Unable to retrieve flavor profile." msgstr "フレーバーのプロファイルを取得できません。" msgid "Unable to retrieve flavor profiles." msgstr "フレーバーのプロファイル一覧を取得できません。" msgid "Unable to retrieve flavor." msgstr "フレーバーを取得できません。" msgid "Unable to retrieve flavors." msgstr "フレーバーの一覧を取得できません。" msgid "Unable to retrieve health monitor." msgstr "ヘルスモニターを取得できません。" msgid "Unable to retrieve health monitors." msgstr "ヘルスモニターの一覧を取得できません。" msgid "Unable to retrieve l7 policies." msgstr "L7 ポリシーの一覧を取得できません。" msgid "Unable to retrieve l7 policy." msgstr "L7 ポリシーを取得できません。" msgid "Unable to retrieve l7 rule." msgstr "L7 ルールを取得できません。" msgid "Unable to retrieve l7 rules." msgstr "L7 ルールの一覧を取得できません。" msgid "Unable to retrieve listener." msgstr "リスナーを取得できません。" msgid "Unable to retrieve listeners." msgstr "リスナーの一覧を取得できません。" msgid "Unable to retrieve load balancer." msgstr "ロードバランサーを取得できません。" msgid "Unable to retrieve load balancers." msgstr "ロードバランサーの一覧を取得できません。" msgid "Unable to retrieve member." msgstr "メンバーを取得できません。" msgid "Unable to retrieve members." msgstr "メンバーの一覧を取得できません。" msgid "Unable to retrieve pool." msgstr "プールを取得できません。" msgid "Unable to retrieve pools." msgstr "プールの一覧を取得できません。" msgid "Unable to retrieve secrets." msgstr "シークレットの一覧を取得できません。" msgid "Unable to update flavor profile." msgstr "フレーバーのプロファイルを更新できません。" msgid "Unable to update flavor." msgstr "フレーバーを更新できません。" msgid "Unable to update health monitor." msgstr "ヘルスモニターを更新できません。" msgid "Unable to update l7 policy." msgstr "L7 ポリシーを更新できません。" msgid "Unable to update l7 rule." msgstr "L7 ルールを更新できません。" msgid "Unable to update listener." msgstr "リスナーを更新できません。" msgid "Unable to update load balancer." msgstr "ロードバランサーを更新できません。" msgid "Unable to update member list." msgstr "メンバーの一覧を更新できません。" msgid "Unable to update member." msgstr "メンバーを更新できません。" msgid "Unable to update pool." msgstr "プールを更新できません。" msgid "Update" msgstr "更新" msgid "Update Health Monitor" msgstr "ヘルスモニターの更新" msgid "Update L7 Policy" msgstr "L7 ポリシーの更新" msgid "Update L7 Rule" msgstr "L7 ルールの更新" msgid "Update Listener" msgstr "リスナーの更新" msgid "Update Load Balancer" msgstr "ロードバランサーの更新" msgid "Update Member" msgstr "メンバーの更新" msgid "Update Pool" msgstr "プールの更新" msgid "Updated At" msgstr "最終更新" msgid "" "Use the key-manager service to create any certificate containers before " "creating the listener.\n" " The following documentation provides information on how to create a " "certificate container:" msgstr "" "リスナーを作成する前に key-manager サービスを使用して証明書のコンテナーを作成" "します。\n" " 以下のドキュメントには、証明書のコンテナーの作成に関する情報が記載されて" "います。" msgid "Value" msgstr "値" msgid "Value:" msgstr "値:" msgid "Weight" msgstr "重み" msgid "Weight:" msgstr "重み:" msgid "" "When true the logic of the rule is inverted. For example, with invert\n" " true, equal to would become not equal to." msgstr "" "true に設定すると、ルールの論理が逆になります。たとえば、反転を true に設定す" "ると、\n" "「等しい」が「等しくない」になります。" msgid "X-Forwarded-For" msgstr "X-Forwarded-For" msgid "X-Forwarded-Port" msgstr "X-Forwarded-Port" msgid "X-Forwarded-Proto" msgstr "X-Forwarded-Proto" msgid "Yes" msgstr "はい" #, python-format msgid "" "You are about to disassociate the floating IP address from load balancer \"%s" "\". Please confirm." msgstr "" "あなたはロードバランサー \"%s\" から Floating IP アドレスの割り当てを解除しよ" "うとしています。確認してください。" #, python-format msgid "You have selected \"%s\". Deleted L7 Policy is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted L7 Policies are not recoverable." msgstr[0] "\"%s\" を選択しました。削除された L7 ポリシーは元に戻せません。" #, python-format msgid "You have selected \"%s\". Deleted L7 Rule is not recoverable." msgid_plural "You have selected \"%s\". Deleted L7 Rules are not recoverable." msgstr[0] "\"%s\" を選択しました。削除された L7 ルールは元に戻せません。" #, python-format msgid "You have selected \"%s\". Deleted health monitor is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted health monitors are not recoverable." msgstr[0] "\"%s\" を選択しました。削除されたヘルスモニターは元に戻せません。" #, python-format msgid "You have selected \"%s\". Deleted listener is not recoverable." msgid_plural "You have selected \"%s\". Deleted listeners are not recoverable." msgstr[0] "\"%s\" を選択しました。削除されたリスナーは元に戻せません。" #, python-format msgid "" "You have selected \"%s\". Deleted load balancer is not recoverable and this " "deletion will delete all of the sub-resources." msgid_plural "" "You have selected \"%s\". Deleted load balancers are not recoverable and " "this deletion will delete all of the sub-resources." msgstr[0] "" "\"%s\" を選択しました。削除されたロードバランサーは元に戻せません。削除するこ" "とで、すべての子リソースも削除されます。" #, python-format msgid "You have selected \"%s\". Deleted member is not recoverable." msgid_plural "You have selected \"%s\". Deleted members are not recoverable." msgstr[0] "\"%s\" を選択しました。削除されたメンバーは元に戻せません。" #, python-format msgid "You have selected \"%s\". Deleted pool is not recoverable." msgid_plural "You have selected \"%s\". Deleted pools are not recoverable." msgstr[0] "\"%s\" を選択しました。削除されたプールは元に戻せません。" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.453101 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ko_KR/0000775000175100017510000000000015033037476023113 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ko_KR/LC_MESSAGES/0000775000175100017510000000000015033037476024700 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ko_KR/LC_MESSAGES/django.po0000664000175100017510000000114615033037474026502 0ustar00mylesmyles# Ian Y. Choi , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2018-02-27 12:38+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-12-06 12:21+0000\n" "Last-Translator: Ian Y. Choi \n" "Language-Team: Korean (South Korea)\n" "Language: ko_KR\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "Load Balancers" msgstr "로드 밸런서" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ko_KR/LC_MESSAGES/djangojs.po0000664000175100017510000012252215033037474027041 0ustar00mylesmyles# Ian Y. Choi , 2017. #zanata # ByungYeol Woo , 2018. #zanata # Ian Y. Choi , 2018. #zanata # Jaewook Oh , 2018. #zanata # Sungjin Kang , 2018. #zanata # ByungYeol Woo , 2019. #zanata # Ian Y. Choi , 2020. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2022-08-16 20:34+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2020-05-05 11:50+0000\n" "Last-Translator: Ian Y. Choi \n" "Language-Team: Korean (South Korea)\n" "Language: ko_KR\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" #, python-format msgid "%(ip)s..." msgstr "%(ip)s..." msgid "A new health monitor is being created." msgstr "새로운 상태 모니터가 생성되고 있습니다." msgid "A new l7 policy is being created." msgstr "새로운 l7 정책이 생성되고 있습니다." msgid "A new listener is being created." msgstr "새로운 리스너를 생성하고 있습니다." msgid "A new load balancer is being created." msgstr "새로운 로드 밸런서를 생성하고 있습니다." msgid "A new pool is being created." msgstr "새로운 풀이 생성되고 있습니다." msgid "" "A pool represents a group of members over which the load balancing will be " "applied." msgstr "풀은 로드 밸런싱이 적용되는 멤버의 그룹을 나타냅니다." msgid "APP_COOKIE: Session persistence based on application cookie." msgstr "APP_COOKIE: 세션 지속성 기반의 어플리케이션 쿠키." msgid "Action" msgstr "Action" msgid "Action:" msgstr "동작:" msgid "Active" msgstr "활성" msgid "Add" msgstr "추가" msgid "Add external member" msgstr "외부 멤버 추가" msgid "Add members to the load balancer pool." msgstr "로드 밸런서 풀에 멤버를 추가합니다." msgid "Add/Remove Members" msgstr "멤버 추가/삭제" msgid "Add/Remove Pool Members" msgstr "풀 멤버 추가/삭제" msgid "" "Additional headers insertion into HTTP header,\n" " only \"X-Forwarded-For\", \"X-Forwarded-Port\" and \"X-Forwarded-Proto\" " "are supported." msgstr "" "HTTP 헤더에 삽입하는 부가적인 헤더에는,\n" " \"X-Forwarded-For\", \"X-Forwarded-Port\", \"X-Forwarded-Proto\"만 지원됩니" "다." msgid "Admin State Up" msgstr "관리자 업 상태" msgid "Algorithm" msgstr "알고리즘" msgid "Algorithm:" msgstr "알고리즘:" msgid "Allocated Members" msgstr "할당된 멤버" msgid "" "An L7 Policy is a collection of L7 rules associated with a Listener, and " "which may also have an association to a back-end pool" msgstr "" "L7 정책은 리스너와 연결된 L7 규칙의 집합이고, 백엔드 풀과 연결되어 있을 수도 " "있습니다." msgid "" "An L7 Rule is a single, simple logical test which returns either true or\n" "false." msgstr "L7 규칙은 참 또는 거짓으로 응답하는 간단한 단일 논리 검사입니다." msgid "" "An alternate IP address used for health monitoring a backend member.\n" " Default is null which monitors the member address." msgstr "" "백엔드 멤버의 상태 모니터링에 사용되는 대체 IP주소입니다.\n" " 멤버 주소를 모니터하는 기본 설정은 null입니다." msgid "" "An alternate protocol port used for health monitoring a backend member.\n" " Default is null which monitors the member protocol port." msgstr "" "백엔드 멤버의 상태 모니터링에 사용되는 대체 프로토콜 포트입니다.\n" " 멤버 프로토콜 포트를 모니터하는 기본 설정은 null입니다." msgid "An error occurred. Please try again later." msgstr "오류가 발생했습니다. 나중에 다시 시도하십시오." msgid "Associate" msgstr "연결" msgid "Associate Floating IP" msgstr "Floating IP 연결" msgid "Associate Floating IP Address" msgstr "Floating IP 주소와 연결" msgid "Associating floating IP with load balancer." msgstr "Floating IP와 로드 밸런서 연결" msgid "Availability Zone" msgstr "가용 구역" msgid "Available Instances" msgstr "사용 가능한 인스턴스" msgid "Backend member connection timeout in milliseconds. Default: 5000." msgstr "백엔드 멤버 연결 타임아웃(밀리 초). 기본 값: 5000." msgid "Backend member inactivity timeout in milliseconds. Default: 50000." msgstr "벡엔드 멤버 비활성 타임아웃 (밀리 초). 기본값: 50000." msgid "Backup" msgstr "백업" msgid "Backup:" msgstr "백업:" msgid "CIDR" msgstr "CIDR" msgid "CONTAINS: String contains." msgstr "CONTAINS: 문자열 포함" msgid "" "COOKIE: The rule looks for a cookie named by the key parameter and\n" " compares it against the value parameter in the rule." msgstr "" "COOKIE: 규칙은 키 매개변수로 이름붙여진 쿠키를 찾고\n" " 규칙 내의 값 매개변수와 비교합니다." msgid "Cancel" msgstr "취소" msgid "Certificate Name" msgstr "인증서 이름" msgid "Client Data Timeout" msgstr "클라이언트 데이터 타임아웃" msgid "Client Data Timeout:" msgstr "클라이언트 데이터 타임아웃:" msgid "Compare Type" msgstr "유형 비교" msgid "Compare Type:" msgstr "유형 비교:" msgid "Confirm Delete Health Monitor" msgid_plural "Confirm Delete Health Monitors" msgstr[0] "상태 모니터 삭제 확인" msgid "Confirm Delete L7 Policy" msgid_plural "Confirm Delete L7 Policies" msgstr[0] "L7 정책 삭제 확인" msgid "Confirm Delete L7 Rule" msgid_plural "Confirm Delete L7 Rules" msgstr[0] "L7 규칙 삭제 확인" msgid "Confirm Delete Listener" msgid_plural "Confirm Delete Listeners" msgstr[0] "리스터 삭제 확인" msgid "Confirm Delete Load Balancer" msgid_plural "Confirm Delete Load Balancers" msgstr[0] "로드 밸런서 삭제 확인" msgid "Confirm Delete Member" msgid_plural "Confirm Delete Members" msgstr[0] "멤버 삭제 확인" msgid "Confirm Delete Pool" msgid_plural "Confirm Delete Pools" msgstr[0] "풀 삭제 확인" msgid "Confirm Disassociate Floating IP Address" msgstr "Floating IP 주소 연결 해제 확인" msgid "Connection Limit" msgstr "연결 제한" msgid "Connection Limit:" msgstr "접속 제한:" msgid "Contains" msgstr "Contains" msgid "Cookie" msgstr "쿠키" msgid "Cookie Name" msgstr "쿠키 이름" msgid "Create Health Monitor" msgstr "상태 모니터 생성" msgid "Create L7 Policy" msgstr "L7 정책 생성" msgid "Create L7 Rule" msgstr "L7 규칙 생성" msgid "Create Listener" msgstr "리스너 생성" msgid "Create Load Balancer" msgstr "로드 밸런서 생성" msgid "Create Pool" msgstr "풀 생성" msgid "Created At" msgstr "생성 시점" msgid "Default Pool ID" msgstr "기본 풀 ID" msgid "Default Pool ID:" msgstr "기본 풀 ID:" msgid "Default TLS Container Ref" msgstr "디폴트 TLS 컨테이너 참조" msgid "Degraded" msgstr "감소됨" msgid "Delay" msgstr "지연" msgid "Delay (sec)" msgstr "지연 (초)" msgid "Delay:" msgstr "지연:" msgid "Delete Health Monitor" msgid_plural "Delete Health Monitors" msgstr[0] "상태 모니터 삭제" msgid "Delete Health Monitors" msgstr "상태 모니터 삭제" msgid "Delete L7 Policies" msgstr "L7 정책 삭제" msgid "Delete L7 Policy" msgid_plural "Delete L7 Policies" msgstr[0] "L7 정책 삭제" msgid "Delete L7 Rule" msgid_plural "Delete L7 Rules" msgstr[0] "L7 규칙 삭제" msgid "Delete L7 Rules" msgstr "L7 규칙 삭제" msgid "Delete Listener" msgid_plural "Delete Listeners" msgstr[0] "리스너 삭제" msgid "Delete Listeners" msgstr "리스너 삭제" msgid "Delete Load Balancer" msgid_plural "Delete Load Balancers" msgstr[0] "로드 밸런서 삭제" msgid "Delete Load Balancers" msgstr "로드 밸런서 삭제" msgid "Delete Member" msgid_plural "Delete Members" msgstr[0] "멤버 삭제" msgid "Delete Members" msgstr "멤버 삭제" msgid "Delete Pool" msgid_plural "Delete Pools" msgstr[0] "풀 삭제" msgid "Delete Pools" msgstr "풀 삭제" #, python-format msgid "Deleted Health Monitor: %s." msgid_plural "Deleted Health Monitors: %s." msgstr[0] "삭제된 상태 모니터: %s." #, python-format msgid "Deleted L7 Policy: %s." msgid_plural "Deleted L7 Policies: %s." msgstr[0] "삭제된 L7 정책: %s." #, python-format msgid "Deleted L7 Rule: %s." msgid_plural "Deleted L7 Rules: %s." msgstr[0] "L7 규칙 삭제됨: %s" #, python-format msgid "Deleted Listener: %s." msgid_plural "Deleted Listeners: %s." msgstr[0] "삭제된 리스너: %s." #, python-format msgid "Deleted Load Balancer: %s." msgid_plural "Deleted Load Balancers: %s." msgstr[0] "로드 밸런서 삭제됨: %s." #, python-format msgid "Deleted Member: %s." msgid_plural "Deleted Members: %s." msgstr[0] "멤버 삭제됨: %s." #, python-format msgid "Deleted Pool: %s." msgid_plural "Deleted Pools: %s." msgstr[0] "삭제된 풀: %s." msgid "Description" msgstr "설명" msgid "Disassociate" msgstr "연결 해제" msgid "Disassociate Floating IP" msgstr "Floating IP 연결 해제" #, python-format msgid "Disassociated floating IP address from load balancer: %s." msgstr "로드 밸런서에서 Floating IP 주소가 연결 해제됨 : %s." msgid "ENDS_WITH: String ends with." msgstr "ENDS_WITH: 문자열로 종료." msgid "EQUAL_TO: String is equal to." msgstr "EQUAL_TO: 문자열과 동일." msgid "" "Each port that listens for traffic on a particular load balancer is " "configured separately and\n" " tied to the load balancer. Multiple listeners can be associated with the " "same load balancer but\n" " each must use a unique port." msgstr "" "특정 로드 밸런서의 트래픽을 수신하는 리스너의 각 포트는 별도로 설정되고\n" " 로드 밸런서에 연결됩니다. 여러 리스너는 동일한 로드 밸런서에 연결될 수 있지" "만\n" " 각각 유일한 포트를 사용해야 합니다." msgid "Edit Health Monitor" msgstr "상태 모니터 편집" msgid "Edit L7 Policy" msgstr "L7 정책 수정" msgid "Edit L7 Rule" msgstr "L7 규칙 수정" msgid "Edit Listener" msgstr "리스터 편집" msgid "Edit Load Balancer" msgstr "로드 밸런서 편집" msgid "Edit Member" msgstr "멤버 편집" msgid "Edit Pool" msgstr "풀 편집" msgid "Ends With" msgstr "Ends With" msgid "Equal To" msgstr "Equal To" msgid "Error" msgstr "에러" msgid "Expected Codes" msgstr "예상 코드" msgid "Expected Codes:" msgstr "예상 코드:" msgid "Expiration Date" msgstr "만기 일자" msgid "" "FILE_TYPE: The rule compares the last portion of the URI against\n" " the value parameter in the rule. (eg. \"txt\", \"jpg\", etc.)" msgstr "" "FILE_TYPE: 규칙은 URI의 마지막 위치와\n" " 규칙 내의 값 매개변수를 비교합니다. (예: \"txt\", \"jpg\" 등)" msgid "File Type" msgstr "파일 타입" msgid "Flavor" msgstr "Flavor" msgid "Flavor Description" msgstr "Flavor 설명" msgid "Flavor ID" msgstr "Flavor ID" msgid "Floating IP" msgstr "플로팅 IP" msgid "Floating IP address or pool" msgstr "플로팅 IP 주소 또는 풀" msgid "Floating IP addresses" msgstr "Floating IP 주소" msgid "Floating IP pools" msgstr "Floating IP 풀" msgid "Frontend client inactivity timeout in milliseconds. Default: 50000." msgstr "프론트엔드 클라이언트의 비활성 타임아웃 (밀리 초). 기본값: 50000." msgid "" "HEADER: The rule looks for a header defined in the key parameter\n" " and compares it against the value parameter in the rule." msgstr "" "HEADER: 규칙은 키 파라미터로 정의된 헤더를 찾고\n" " 규칙 내의 값 매개변수와 비교합니다." msgid "" "HOST_NAME: The rule does a comparison between the HTTP/1.1\n" " hostname in the request against the value parameter in the rule." msgstr "" "HOST_NAME: 규칙은 요청의 HTTP/1.1 호스트이름과\n" " 규칙 내의 값 매개변수를 비교합니다." msgid "HTTP Method" msgstr "HTTP 메서드" msgid "HTTP Method:" msgstr "HTTP 메소드:" msgid "HTTP_COOKIE: Session persistence based on http cookie." msgstr "HTTP_COOKIE: 세션 지속성 기반의 http 쿠키." msgid "Header" msgstr "해더" msgid "Health Monitor" msgstr "상태 모니터" msgid "Health Monitor ID" msgstr "상태 모니터 ID" msgid "Health Monitors" msgstr "상태 모니터" msgid "Host Name" msgstr "호스트 이름" msgid "ID" msgstr "ID" msgid "IP Address" msgstr "IP 주소" #, python-format msgid "IP Addresses (%(count)s)" msgstr "IP 주소 (%(count)s)" msgid "IP address" msgstr "IP 주소" msgid "IP address:" msgstr "IP 주소:" msgid "" "If an IP address is provided it must be a well-formed IPv4 or IPv6 address. " "The system will\n" " attempt to assign the provided IP address to the load balancer. If an IP " "address is not provided\n" " then one will be allocated for you." msgstr "" " IP 주소가 제공된 경우 올바른 형식의 IPv4 또는 IPv6 주소여야합니다. 시스템" "은\n" " 제공된 IP 주소를 로드 밸런서에 할당하려고 시도합니다. IP 주소가 제공되지 " "않은 경우\n" " 하나가 할당될 것입니다." msgid "" "If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL " "certificates must\n" " be selected. The first certificate will be the default." msgstr "" "만약 리스너가 TERMINATED_HTTPS 프로토콜을 사용한다면, 하나 이상의 SSL 인증서" "가 \n" "선택되어야 합니다. 첫 인증서는 기본값이 됩니다." msgid "Inactive" msgstr "비활성" msgid "Insert Headers" msgstr "헤더 삽입" msgid "Insert Headers:" msgstr "헤더 추가:" msgid "Invert" msgstr "반전" msgid "Invert:" msgstr "반전:" msgid "" "Is the member a backup? Backup members only receive traffic when all\n" " non-backup members are down." msgstr "" "멤버가 백업인가요? 백업 멤버는 모든 비 백업 멤버가 다운됐을 때만\n" " 트래픽을 수신합니다." msgid "Key" msgstr "키" msgid "Key Manager API Guide: Creating a Certificate Container" msgstr "키 관리자 API 가이드: 인증서 컨테이너 생성하기" msgid "Key Manager Service Command-Line Client" msgstr "키 관리자 서비스 커맨드라인 클라이언트" msgid "Key:" msgstr "키:" msgid "L7 Policies" msgstr "L7 정책" msgid "L7 Policy" msgstr "L7 정책" msgid "L7 Policy Details" msgstr "L7 정책 상세 정보" msgid "L7 Rule" msgstr "l7 규칙" msgid "L7 Rule Details" msgstr "L7 규칙 상세 정보" msgid "L7 Rules" msgstr "L7 규칙" msgid "" "LEAST_CONNECTIONS: Allocates requests to the instance with the least number " "of active\n" " connections." msgstr "" "LEAST_CONNECTIONS: 활성화된 연결이 가장 적은 인스턴스로\n" " 요청을 할당합니다." msgid "Least Connections" msgstr "최소 연결" msgid "Listener" msgstr "리스너" msgid "Listener Details" msgstr "리스너 세부정보" msgid "Listener ID" msgstr "리스너 ID" msgid "Listeners" msgstr "리스너" msgid "Load Balancer" msgstr "로드 밸런서" msgid "Load Balancer Details" msgstr "로드 밸런서 세부정보" msgid "Load Balancers" msgstr "로드 밸런서" msgid "Loading" msgstr "불러오는 중" msgid "Max Retries" msgstr "최대 재시도" msgid "Max Retries Down" msgstr "최대 재시도 다운" msgid "Max Retries Down:" msgstr "최대 재시도 다운:" msgid "Max Retries:" msgstr "최대 재시도:" msgid "Member" msgstr "멤버" msgid "Member Connect Timeout" msgstr "멤버 연결 타임아웃" msgid "Member Connect Timeout:" msgstr "멤버 연결 타임아웃:" msgid "Member Data Timeout" msgstr "멤버 데이터 타임아웃" msgid "Member Data Timeout:" msgstr "멤버 데이터 타임아웃:" msgid "Members" msgstr "멤버" msgid "" "Members are the actual IP addresses that will receive traffic from the load " "balancer. Each\n" " member must have a unique combination of IP address and port." msgstr "" "멤버는 로드 밸런서에서 트래픽을 받게 되는 실제 IP 주소입니다.\n" " 각 멤버는 유일한 IP 주소와 포트의 조합을 가지고 있어야 합니다." msgid "Monitor Address" msgstr "모니터 주소" msgid "Monitor Address:" msgstr "모니터 주소:" msgid "Monitor Details" msgstr "모니터 세부 정보" msgid "Monitor Port" msgstr "모니터 포트" msgid "Monitor Port:" msgstr "모니터 포트:" msgid "Name" msgstr "이름" msgid "Network" msgstr "네트워크" msgid "Network ID" msgstr "네트워크 ID" msgid "No" msgstr "아니오" msgid "No Monitor" msgstr "모니터 없음" msgid "No available certificates" msgstr "이용 가능한 인증서가 없음" msgid "No available instances" msgstr "사용 가능한 인스턴스가 없음" msgid "No items to display." msgstr "표시할 항목이 없습니다." msgid "No matching options" msgstr "매칭되는 옵션이 없음" msgid "No members have been allocated" msgstr "할당된 멤버가 없음" msgid "None" msgstr "없음" msgid "Offline" msgstr "오프라인" msgid "Online" msgstr "온라인" msgid "Operating Status" msgstr "운영 상태" msgid "Overview" msgstr "개요" msgid "" "PATH: The rule compares the path portion of the HTTP URI against\n" " the value parameter in the rule." msgstr "" "PATH: 규칙은 HTTP URI의 경로 위치와\n" " 규칙 내의 값 매개변수를 비교합니다." msgid "Path" msgstr "경로" msgid "Pending Create" msgstr "생성 대기중" msgid "Pending Delete" msgstr "삭제 대기중" msgid "Pending Update" msgstr "업데이트 대기중" msgid "Please Wait" msgstr "기다려 주십시오" msgid "Pool" msgstr "풀" msgid "Pool Details" msgstr "풀 세부 정보" msgid "Pool Members" msgstr "풀 멤버" msgid "Pool member has been updated." msgstr "풀 멤버가 업데이트 되었습니다." msgid "Pools" msgstr "풀" msgid "Port" msgstr "포트" msgid "Port ID" msgstr "포트 ID" msgid "Port:" msgstr "포트:" msgid "Position" msgstr "위치" msgid "Position:" msgstr "위치: " msgid "Project" msgstr "프로젝트" msgid "Project ID" msgstr "프로젝트 ID" msgid "Protocol" msgstr "프로토콜" msgid "Protocol Port" msgstr "프로토콜 포트" msgid "Protocol:" msgstr "프로토콜:" msgid "Provide the details for the health monitor." msgstr "상태 모니터의 세부 사항을 제공하십시오." msgid "Provide the details for the l7 policy." msgstr "L7 정책의 세부 사항을 제공하세요." msgid "Provide the details for the l7 rule." msgstr "L7 규칙에 대한 세부 사항 제공." msgid "Provide the details for the listener." msgstr "리스너에 대한 자세한 정보를 제공하십시오." msgid "Provide the details for the load balancer." msgstr "로드 밸런서에 대한 자세한 정보를 제공하십시오." msgid "Provide the details for the member." msgstr "멤버에 대한 세부 사항을 제공하십시오." msgid "Provide the details for the pool." msgstr "풀에 대한 세부 사항을 제공하십시오." msgid "Provider" msgstr "프로바이더" msgid "Provisioning Status" msgstr "프로비저닝 상태" msgid "" "REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated " "with the L7 policy." msgstr "REDIRECT_TO_POOL: 요청은 L7 정책과 함께 연결된 백엔드 풀로 전달됩니다." msgid "" "REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in " "the redirect_url parameter." msgstr "" "REDIRECT_TO_URL: redirect_url 매개변수에 정의된 URL로 HTTP 리디렉션이 요청자" "에게 전송됩니다." msgid "REGEX: Perl type regular expression matching." msgstr "REGEX: 펄 유형의 정규 표현식 일치." msgid "" "REJECT: The request is denied with an appropriate response code, and not " "forwarded on to any back-end pool." msgstr "" "REJECT: 요청은 적절한 응답 코드로 거부되고, 어떠한 백엔드 풀로도 전달되지 않" "습니다." msgid "ROUND_ROBIN: Rotates requests evenly between multiple instances." msgstr "ROUND_ROBIN: 여러 인스턴스들 사이에서 짝수로 요청을 순환합니다." msgid "Redirect Pool ID" msgstr "리디렉션 풀 ID" msgid "Redirect Pool ID:" msgstr "리디렉션 풀 ID:" msgid "Redirect URL" msgstr "리디렉션 URL" msgid "Redirect URL:" msgstr "리디렉션 URL:" msgid "Redirect to Pool" msgstr "풀로 리디렉션" msgid "Redirect to URL" msgstr "URL로 리디렉션" msgid "Regex" msgstr "정규표현식" msgid "Reject" msgstr "거부" msgid "Remove" msgstr "제거" msgid "" "Requests matching this policy will be redirected to the pool with this ID. " "Only valid if action is REDIRECT_TO_POOL." msgstr "" "이 정책에 매칭되는 요청은 이 ID로 풀에 리디렉트 됩니다. REDIRECT_TO_POOL 동작" "일때만 유효합니다." msgid "" "Requests matching this policy will be redirected to this URL. Only valid if " "action is REDIRECT_TO_URL." msgstr "" "이 정책에 매칭되는 요청은 이 URL로 리디렉트 됩니다. REDIRECT_TO_URL 동작일때" "만 유효합니다." msgid "Round Robin" msgstr "라운드 로빈" msgid "Rules" msgstr "규칙" msgid "SNI Container Refs" msgstr "SNI 컨테이너 참조" msgid "" "SOURCE_IP: Requests from a unique source IP address are consistently " "directed to the same instance." msgstr "" "SOURCE_IP: 하나의 고유한 소스 IP 주소로부터의 요청들은 지속적으로 같은 인스턴" "스로 이동합니다." msgid "SOURCE_IP: Session persistence based on source ip." msgstr "SOURCE_IP: 세션 지속성 기반의 소스 ip." msgid "SSL Certificates" msgstr "SSL 인증서" msgid "STARTS_WITH: String starts with." msgstr "STARTS_WITH: 문자열로 시작." msgid "" "Select a floating IP address to associate with the load balancer or a " "floating IP pool in which to allocate a new floating IP address." msgstr "" "로드밸런서나 Floating IP 풀과 연결하기 위하여 Floating IP 주소를 선택합니다." msgid "Select certificates from the available certificates below" msgstr "아래의 이용 가능한 인증서 중에서 선택" msgid "Select one or more SSL certificates for the listener." msgstr "리스너에 대한 하나 이상의 SSL 인증서를 선택하십시오." msgid "Session Persistence" msgstr "세션 지속성" msgid "Session Persistence:" msgstr "세션 지속성:" msgid "Source IP" msgstr "소스 IP" msgid "Starts With" msgstr "Starts With" msgid "Subnet" msgstr "서브넷" msgid "Subnet ID" msgstr "서브넷 ID" msgid "Subnet:" msgstr "서브넷:" msgid "TCP Inspect Timeout" msgstr "TCP 검사 타임아웃" msgid "TCP Inspect Timeout:" msgstr "TCP 검사 타임아웃:" msgid "" "The Available Instances table contains existing compute instances that can " "be added as members\n" " of the pool. Use the \"Add external member\" button to add a member not " "found in the Available\n" " Instances table." msgstr "" "사용 가능한 인스턴스 테이블에는 풀의 멤버로 추가될 수 있고 존재하는 컴퓨트 인" "스턴스가 \n" " 포함되어 있습니다. 사용 가능한 인스턴스 테이블에 없는 멤버를 추가하기 위하" "여 \n" " \"외부 멤버 추가\" 버튼을 사용하시오" msgid "The HTTP method used to perform the health check." msgstr "상태 체크를 수행하기 위한 HTTP 메소드." msgid "The ID of the pool used by the listener if no L7 policies match." msgstr "매칭되는 L7 정책이 없는 경우 리스너에서 사용하는 풀 ID" msgid "The IP address is not valid." msgstr "IP 주소가 유효하지 않습니다." msgid "" "The IP address of the member to receive traffic from the load balancer. Must " "be a well-formed\n" " IPv4 or IPv6 address." msgstr "" "로드 밸런서에서 트래픽을 받는 멤버의 IP 주소입니다. 양식에 맞는 \n" " IPv4나 IPv6 주소이어야 합니다." msgid "" "The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL." msgstr "L7 정책 동작. REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL 중 하나." msgid "The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH." msgstr "L7 규칙 유형. COOKIE, FILE_TYPE, HEADER, HOST_NAME, PATH 중 하나." msgid "The URL path is not valid." msgstr "URL 경로가 유효하지 않습니다." msgid "" "The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, or STARTS_WITH." msgstr "" "L7 규칙의 비교 유형. CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, STARTS_WITH 중 하나." msgid "The connection limit must be a number greater than or equal to -1." msgstr "접속 제한은 -1 이상이어야 합니다." msgid "" "The expected HTTP status codes to get from a successful health check. Must " "be a single number,\n" " a comma separated list of numbers, or a range (two numbers separated by a " "hyphen)." msgstr "" "상태 체크가 성공했을 때 수신하게 되는 HTTP 상태 코드입니다. 단일 숫자이어야 " "하고,\n" " 쉼표로 구분된 숫자 리스트이거나 두 개의 숫자가 하이픈으로 구별된 범주이어" "야 합니다." msgid "The expected status code is not valid." msgstr "예상된 상태 코드가 유효하지 않습니다." msgid "The health check interval must be greater than or equal to the timeout." msgstr "상태 체크 간격은 타임아웃 값 이상이어야 합니다." msgid "The health monitor has been updated." msgstr "상태 모니터가 업데이트 되었습니다." msgid "" "The health monitor is used to determine the health of your pool members. " "Health checks\n" " routinely run against each member within the pool and the result of the " "health check is used\n" " to determine if the member receives new connections. Each pool can only " "have one health\n" " monitor." msgstr "" "상태 모니터는 풀 멤버의 상태를 결정하는 데 사용됩니다. 상태 체크는\n" " 풀 내의 각 멤버에 대해 주기적으로 실행하고, 상태 체크 결과로 \n" " 멤버가 새 연결을 받을 수 있는지를 결정합니다. 각 풀은 하나의 상태 모니터" "만 \n" " 가질 수 있습니다." msgid "" "The interval between health checks. Must be greater than or equal to the " "timeout." msgstr "상태 체크 사이의 간격. 타임아웃 설정값 이상이어야 합니다." msgid "" "The key to use for the comparison. For example, the name of the cookie\n" " to evaluate." msgstr "" "비교에 사용되는 키. 예를 들어, 평가에 사용될\n" " 쿠키의 이름." msgid "The l7policy has been updated." msgstr "L7 정책이 업데이트 되었습니다." msgid "The l7rule has been updated." msgstr "L7 규칙이 업데이트 되었습니다." msgid "The listener has been updated." msgstr "리스너가 업데이트 되었습니다." msgid "" "The load balancer algorithm that distributes traffic to the pool members." msgstr "풀 멤버에게 트래픽을 분배시키는 로드 밸런서 알고리즘." msgid "The load balancer has been updated." msgstr "로드 밸런서가 업데이트 되었습니다." msgid "" "The load balancer occupies a neutron network port and has an IP address " "assigned from a subnet." msgstr "" "로드 밸런서는 뉴트론 네트워크 포트를 사용하고 서브넷에서 할당된 IP를 가집니" "다." msgid "The max retry count must be a number between 1 and 10." msgstr "최대 재시도 횟수는 1 ~ 10 사이입니다." msgid "The max retry down count must be a number between 1 and 10." msgstr "최대 재시도 횟수는 1 ~ 10 사이입니다." msgid "" "The maximum number of connections permitted for this listener.\n" " Default value is -1 which represents infinite connections." msgstr "" "이 리스너에 허용된 최대 접속 제한 수.\n" " 기본 값은 -1이고, 이는 무제한을 나타냅니다." msgid "The monitor address must be a valid IP address." msgstr "모니터 주소는 유효한 IP 주소이어야 합니다." msgid "The monitor port must be a number between 1 and 65535." msgstr "모니터 포트는 반드시 1 ~ 65535 사이의 숫자이어야 합니다." msgid "The network on which to allocate the load balancer's IP address." msgstr "로드 밸런서의 IP 주소를 할당하기 위한 네트워크" msgid "The network which contains the IP address of the member." msgstr "멤버의 IP 주소를 포함하고 있는 네트워크입니다." msgid "" "The number of allowed connection failures before marking the member as " "error. Must be a\n" " number from 1 to 10. The default is 3." msgstr "" "재시도 횟수를 초과하여 연결이 실패하면 멤버는 에러 상태가 되고, 재시도 횟수" "는\n" " 1에서 10까지의 숫자이어야 합니다. 기본 값은 3." msgid "" "The number of allowed connection failures before marking the member as " "inactive. Must be a\n" " number from 1 to 10." msgstr "" "재시도 횟수를 초과하여 연결이 실패하면 멤버는 비활성화 되고, 재시도 횟수는\n" " 1에서 10까지의 숫자이어야 합니다." msgid "The pool has been updated." msgstr "풀이 업데이트 되었습니다." msgid "The pool members have been updated." msgstr "풀 멤버가 업데이트 되었습니다." msgid "The port must be a number between 1 and 65535." msgstr "포트 번호는 1 ~ 65535 사이 숫자이어야 합니다." msgid "" "The port must be unique among all listeners attached to this load balancer." msgstr "이 로드 밸런서에 연결되는 모든 리스너에서 포트는 유일해야 합니다." msgid "" "The port on which the front end listens. Must be an integer from 1 to 65535." msgstr "프런트 엔드에서 listen하는 포트. 1에서 65535 사이의 정수여야 합니다." msgid "" "The port on which the member listens for traffic. Must be a number from 1 to " "65535." msgstr "" "트래픽을 수신하는 멤버의 포트 번호입니다. 포트 번호는 1 ~ 65535 사이 숫자이어" "야 합니다." msgid "The position must be a number between 1 and 2147483647." msgstr "위치는 1에서 2147483647까지의 숫자여야 합니다." msgid "The position of this policy on the listener. Positions start at 1." msgstr "리스너에서의 이 정책의 위치. 위치는 1에서 시작합니다." msgid "" "The protocol for which the front end listens. The TERMINATED_HTTPS protocol " "is only available if\n" " the key-manager service is enabled and you have authority to list " "certificate containers and\n" " secrets." msgstr "" "프런트 엔드에서 수신하는 프로토콜. TERMINATED_HTTPS 프로토콜은\n" " key-manager 서비스가 활성화되고 인증서 컨테이너와 비밀값을 리스트할 수 있" "는 \n" " 권한이 있어야 이용이 가능합니다." msgid "The redirect url must be a valid http or https url." msgstr "리디렉션 url은 유효한 http 또는 https url이어야 합니다." msgid "" "The target of the health check HTTP request to the member. Must be a valid " "URL path." msgstr "" "상태 체크하기 위해 멤버에게 HTTP 요청하는 대상. 유효한 URL 경로이어야 합니다." msgid "" "The time after which a health check times out. Must be a number greater than " "or equal to 0\n" " and less than or equal to the interval." msgstr "" "상태 체크 시간이 종료되는 시간. 0 이상의 숫자이어야 하고\n" " 타임아웃 값은 상태 체크 간격 값 이하이어야 합니다." msgid "The timeout must be a number between 0 and 31536000000." msgstr "타임아웃은 0에서 3153600000까지의 숫자여야 합니다." msgid "The timeout must be a number greater than or equal to 0." msgstr "타임아웃 시간은 0 이상이어야 합니다." msgid "" "The type of session persistence for distributing traffic to the pool members." msgstr "풀 펨버에게 트래픽을 분배시키는 세션 지속성 유형." msgid "" "The value to use for the comparison. For example, the file type to compare." msgstr "비교에 사용되는 키. 예를 들어, 비교에 사용되는 파일 유형." msgid "" "Time, in milliseconds, to wait for additional TCP packets for content\n" " inspection. Default: 0." msgstr "" "컨텐츠 검사 용으로 부가적인 TCP 패킷을 기다리기 위한\n" " 시간 (밀리 초). 기본값: 0." msgid "Timeout" msgstr "제한시간" msgid "Timeout (sec)" msgstr "타임아웃 (초)" msgid "Timeout:" msgstr "타임아웃:" msgid "Type" msgstr "유형" msgid "Type:" msgstr "유형:" msgid "URL Path" msgstr "URL 경로" msgid "URL Path:" msgstr "URL 경로:" msgid "Unable to create flavor profile." msgstr "Flavor 프로필을 생성할 수 없습니다." msgid "Unable to create flavor." msgstr "Flavor를 생성할 수 없습니다." msgid "Unable to create health monitor." msgstr "상태 모니터를 생성할 수 없습니다." msgid "Unable to create l7 policy." msgstr "L7 정책을 생성하지 못했습니다." msgid "Unable to create l7 rule." msgstr "L7 규칙을 생성하지 못했습니다." msgid "Unable to create listener." msgstr "리스너를 생성할 수 없습니다." msgid "Unable to create load balancer." msgstr "로드 밸런서를 생성할 수 없습니다." msgid "Unable to create pool." msgstr "풀을 생성할 수 없습니다." #, python-format msgid "Unable to delete Health Monitor: %s." msgid_plural "Unable to delete Health Monitors: %s." msgstr[0] "상태 모니터를 삭제할 수 없습니다: %s." #, python-format msgid "Unable to delete L7 Policy: %s." msgid_plural "Unable to delete L7 Policies: %s." msgstr[0] "L7 정책을 삭제할 수 없습니다: %s." #, python-format msgid "Unable to delete L7 Rule: %s." msgid_plural "Unable to delete L7 Rules: %s." msgstr[0] "L7 규칙을 삭제할 수 없습니다: %s" #, python-format msgid "Unable to delete Listener: %s." msgid_plural "Unable to delete Listeners: %s." msgstr[0] "리스너를 삭제할 수 없습니다: %s." #, python-format msgid "Unable to delete Load Balancer: %s." msgid_plural "Unable to delete Load Balancers: %s." msgstr[0] "로드 밸런서를 삭제할 수 없습니다: %s." #, python-format msgid "Unable to delete Member: %s." msgid_plural "Unable to delete Members: %s." msgstr[0] "멤버를 삭제할 수 없습니다: %s." #, python-format msgid "Unable to delete Pool: %s." msgid_plural "Unable to delete Pools: %s." msgstr[0] "다음 풀을 삭제할 수 없습니다: %s." msgid "Unable to delete flavor profile." msgstr "Flavor 프로필을 삭제할 수 없습니다." msgid "Unable to delete flavor." msgstr "Flavor를 삭제할 수 없습니다." msgid "Unable to delete health monitor." msgstr "상태 모니터를 삭제할 수 없습니다." msgid "Unable to delete l7 policy." msgstr "L7 정책을 삭제하지 못했습니다." msgid "Unable to delete l7 rule." msgstr "L7 규칙을 삭제하지 못했습니다." msgid "Unable to delete listener." msgstr "리스너를 삭제할 수 없습니다." msgid "Unable to delete load balancer." msgstr "로드 밸런서를 삭제할 수 없습니다." msgid "Unable to delete member." msgstr "멤버를 삭제할 수 없습니다." msgid "Unable to delete pool." msgstr "풀을 삭제할 수 없습니다." #, python-format msgid "Unable to disassociate floating IP address from load balancer: %s." msgstr "다음 로드 밸런서에서 Floating IP를 연결 해제 할 수 없습니다: %s" msgid "Unable to retrieve SSL certificates." msgstr "SSL 인증을 가져올 수 없습니다." msgid "Unable to retrieve availability zones." msgstr "가용 구역을 가져올 수 없습니다." msgid "Unable to retrieve flavor profile." msgstr "Flavor 프로필을 가져올 수 없습니다." msgid "Unable to retrieve flavor profiles." msgstr "Flavor 프로필을 가져올 수 없습니다." msgid "Unable to retrieve flavor." msgstr "Flavor를 가져올 수 없습니다." msgid "Unable to retrieve flavors." msgstr "Flavor를 가져올 수 없습니다." msgid "Unable to retrieve health monitor." msgstr "상태 모니터를 가져올 수 없습니다." msgid "Unable to retrieve health monitors." msgstr "상태 모니터를 가져올 수 없습니다." msgid "Unable to retrieve l7 policies." msgstr "L7 정책들을 찾을 수 없습니다." msgid "Unable to retrieve l7 policy." msgstr "L7 정책을 찾을 수 없습니다." msgid "Unable to retrieve l7 rule." msgstr "L7 규칙을 찾을 수 없습니다." msgid "Unable to retrieve l7 rules." msgstr "L7 규칙들을 찾을 수 없습니다." msgid "Unable to retrieve listener." msgstr "리스너를 가져올 수 없습니다." msgid "Unable to retrieve listeners." msgstr "리스너를 가져올 수 없습니다." msgid "Unable to retrieve load balancer." msgstr "로드 밸런서를 가져올 수 없습니다." msgid "Unable to retrieve load balancers." msgstr "로드 밸런서를 가져올 수 없습니다." msgid "Unable to retrieve member." msgstr "멤버를 가져올 수 없습니다." msgid "Unable to retrieve members." msgstr "멤버를 가져올 수 없습니다." msgid "Unable to retrieve pool." msgstr "풀을 가져올 수 없습니다." msgid "Unable to retrieve pools." msgstr "풀을 가져올 수 없습니다." msgid "Unable to retrieve secrets." msgstr "비밀키를 가져올 수 없습니다." msgid "Unable to update flavor profile." msgstr "Flavor 프로필을 업데이트할 수 없습니다." msgid "Unable to update flavor." msgstr "Flavor를 업데이트할 수 없습니다." msgid "Unable to update health monitor." msgstr "상태 모니터를 업데이트할 수 없습니다." msgid "Unable to update l7 policy." msgstr "L7 정책을 갱신하지 못했습니다." msgid "Unable to update l7 rule." msgstr "L7 규칙을 갱신하지 못했습니다." msgid "Unable to update listener." msgstr "리스너를 업데이트할 수 없습니다." msgid "Unable to update load balancer." msgstr "로드 밸런서를 업데이트할 수 없습니다. " msgid "Unable to update member list." msgstr "멤버 목록을 업데이트할 수 없습니다." msgid "Unable to update member." msgstr "멤버를 업데이트할 수 없습니다." msgid "Unable to update pool." msgstr "풀을 업데이트할 수 없습니다." msgid "Update" msgstr "업데이트" msgid "Update Health Monitor" msgstr "상태 모니터 업데이트" msgid "Update L7 Policy" msgstr "L7 정책 업데이트" msgid "Update L7 Rule" msgstr "L7 규칙 업데이트" msgid "Update Listener" msgstr "리스너 업데이트" msgid "Update Load Balancer" msgstr "로드 밸런서 업데이트" msgid "Update Member" msgstr "멤버 업데이트" msgid "Update Pool" msgstr "풀 업데이트" msgid "Updated At" msgstr "업데이트" msgid "" "Use the key-manager service to create any certificate containers before " "creating the listener.\n" " The following documentation provides information on how to create a " "certificate container:" msgstr "" "리스너를 만들기 전에 인증서 컨테이너를 만들기 위해 키 관리자 서비스를 사용하" "세요.\n" " 다음 문서는 인증서 컨테이너를 어떻게 만드는지에 대한 정보를 제공합니다:" msgid "Value" msgstr "값" msgid "Value:" msgstr "값:" msgid "Weight" msgstr "가중치" msgid "Weight:" msgstr "가중치:" msgid "" "When true the logic of the rule is inverted. For example, with invert\n" " true, equal to would become not equal to." msgstr "" "값이 참일 때 규칙의 논리가 반전됩니다. 예를 들어,\n" " invert true일 때, equal to는 not equal to가 됩니다." msgid "X-Forwarded-For" msgstr "X-Forwarded-For" msgid "X-Forwarded-Port" msgstr "X-Forwarded-Port" msgid "X-Forwarded-Proto" msgstr "X-Forwarded-Proto" msgid "Yes" msgstr "예" #, python-format msgid "" "You are about to disassociate the floating IP address from load balancer \"%s" "\". Please confirm." msgstr "" "Floating IP 주소를 로드 밸런서 \"%s\"에서 연결 해제하려고 합니다. 확인해주세" "요. " #, python-format msgid "You have selected \"%s\". Deleted L7 Policy is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted L7 Policies are not recoverable." msgstr[0] "\"%s\" 를 선택하였습니다. 삭제된 L7 정책은 복구할 수 없습니다." #, python-format msgid "You have selected \"%s\". Deleted L7 Rule is not recoverable." msgid_plural "You have selected \"%s\". Deleted L7 Rules are not recoverable." msgstr[0] "\"%s\" 를 선택했습니다. 삭제된 L7 규칙은 복구할 수 없습니다." #, python-format msgid "You have selected \"%s\". Deleted health monitor is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted health monitors are not recoverable." msgstr[0] "\"%s\"를 선택했습니다. 삭제된 상태 모니터는 복구할 수 없습니다." #, python-format msgid "You have selected \"%s\". Deleted listener is not recoverable." msgid_plural "You have selected \"%s\". Deleted listeners are not recoverable." msgstr[0] "\"%s\"를 선택했습니다. 삭제된 리스너는 복구할 수 없습니다." #, python-format msgid "" "You have selected \"%s\". Deleted load balancer is not recoverable and this " "deletion will delete all of the sub-resources." msgid_plural "" "You have selected \"%s\". Deleted load balancers are not recoverable and " "this deletion will delete all of the sub-resources." msgstr[0] "" "\"%s\"를 선택했습니다. 삭제된 로드 밸런서는 복구할 수 없고 모든 하부 리소스" "도 함께 삭제됩니다." #, python-format msgid "You have selected \"%s\". Deleted member is not recoverable." msgid_plural "You have selected \"%s\". Deleted members are not recoverable." msgstr[0] "\"%s\"를 선택했습니다. 삭제된 멤버는 복구되지 않습니다." #, python-format msgid "You have selected \"%s\". Deleted pool is not recoverable." msgid_plural "You have selected \"%s\". Deleted pools are not recoverable." msgstr[0] "\"%s\"를 선택했습니다. 삭제된 풀은 복구되지 않습니다." ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.453101 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/pt_BR/0000775000175100017510000000000015033037476023114 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/pt_BR/LC_MESSAGES/0000775000175100017510000000000015033037476024701 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/pt_BR/LC_MESSAGES/django.po0000664000175100017510000000121615033037474026501 0ustar00mylesmyles# Fernando Pimenta , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2018-03-17 18:17+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-03-21 10:36+0000\n" "Last-Translator: Fernando Pimenta \n" "Language-Team: Portuguese (Brazil)\n" "Language: pt_BR\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "Load Balancers" msgstr "Balanceadores de Carga" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.453101 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ru/0000775000175100017510000000000015033037476022534 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ru/LC_MESSAGES/0000775000175100017510000000000015033037476024321 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ru/LC_MESSAGES/django.po0000664000175100017510000002051015033037474026117 0ustar00mylesmyles# Artem , 2016. #zanata # Fedor Tarasenko , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard 1.0.1.dev55\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2017-02-03 18:54+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-02-03 08:54+0000\n" "Last-Translator: Fedor Tarasenko \n" "Language-Team: Russian\n" "Language: ru\n" "X-Generator: Zanata 3.7.3\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" #, python-format msgid "%s loadbalancers" msgstr "%s балансировщики нагрузки" msgid "Admin Status" msgstr "Статус" msgid "All Instances" msgstr "Все инстансы" msgid "Certificate" msgstr "Сертификат" msgid "Certificate Chain (Optional)" msgstr "Цепочка сертификатов (Необязательно)" msgid "Certificate Name" msgstr "Имя сертификата" msgid "Could not create full loadbalancer." msgstr "Невозможно создать полноценный балансировщик нагрузки." msgid "Could not get load balancer list." msgstr "Невозможно получить список балансировщиков нагрузки." msgid "Disable" msgstr "Выключить" msgid "Disabled LB" msgstr "Отключённые балансировщики" msgid "Edit Load Balancer" msgstr "Редактировать балансировщик нагрузки" msgid "Enable" msgstr "Включить" msgid "Enabled LB" msgstr "Включённые балансировщики" msgid "HTTP" msgstr "HTTP" msgid "HTTPS" msgstr "HTTPS" msgid "Health Check Interval (in seconds)" msgstr "Интервал проверки статуса (сек)" msgid "IP" msgstr "IP-адрес" msgid "Instance Port" msgstr "Порт инстанса" msgid "Instance Port on which service is running." msgstr "Порт инстанса на котором запущена служба" msgid "Instances" msgstr "Инстансы" msgid "Intermediate Chain Certificates" msgstr "Цепочка промежуточных сертификатов" msgid "LB Details" msgstr "Детали балансировщика" msgid "LB Port" msgstr "Порт балансировки" msgid "LB Port on which LB is listening." msgstr "Порт балансировщика для обработки входящих подключений" msgid "LB Protocol" msgstr "Протокол балансировки" msgid "Launch" msgstr "Запустить" msgid "Launch Load Balancer" msgstr "Запустить балансировщик нагрузки" #, python-format msgid "Launched %(count)s named \"%(name)s\"." msgstr "Запущено %(count)s \"%(name)s\"." msgid "Least Connection" msgstr "Минимум соединений" msgid "Least Sessions" msgstr "Минимум сессий" msgid "Load Balancer" msgstr "Балансировщик нагрузки" msgid "Load Balancer Description" msgstr "Описание балансировщика нагрузки" msgid "Load Balancers" msgstr "Балансировщики нагрузки" msgid "Load Balancers V2" msgstr "Балансировщики нагрузки V2" msgid "Load Balancing Method" msgstr "Метод балансировки нагрузки" msgid "Method" msgstr "Метод" msgid "Monitor" msgstr "Монитор" msgid "Name" msgstr "Имя" msgid "No instances found." msgstr "Инстансы не найдены." msgid "No members enabled." msgstr "Нет разрешенных участников." msgid "Not available" msgstr "Недоступно" msgid "" "Number of times health check should be attempted before marking down a member" msgstr "" "Количество проверок доступности перед тем, как пометить участника недоступным" msgid "Operating Status" msgstr "Рабочее состояние" msgid "Overview" msgstr "Обзор" msgid "PING" msgstr "PING" msgid "Please provide all certificate parameters." msgstr "Предоставьте все параметры сертификата." msgid "Please provide instance port" msgstr "Укажите порт инстанса" msgid "" "Please select a list of instances that should handle traffic for this target " "load balancer. All instances must reside in the same Project as the target " "load balancer." msgstr "" "Выберите инстансы, обрабатывающие трафик целевого балансировщика нагрузки. " "Все инстансы должны находиться в том же проекте, что и балансировщик." msgid "Please select an option for the load balancing method." msgstr "Выберите метод балансировки нагрузки." msgid "Please select at least one member" msgstr "Выберите как минимум одного участника" msgid "Private Key" msgstr "Закрытый ключ" msgid "Protocol" msgstr "Протокол" msgid "Provide Load Balancer Description." msgstr "Предоставьте описание балансировщика нагрузки." msgid "Provisioning Status" msgstr "Статус развертывания" msgid "Receive String" msgstr "Строка ответа" #, python-format msgid "Requested IP and port combination already exists %s " msgstr "Запрошенная комбинация IP и порта уже существует %s" msgid "Retry count before markdown" msgstr "Количество попыток перед отключением" msgid "Round Robin" msgstr "Циклический" msgid "SSL" msgstr "SSL" msgid "SSL Certificate" msgstr " SSL сертификат" msgid "Scheduled termination of" msgstr "Запланировано удаление" msgid "Select from existing VIP IPs" msgstr "Выберите из существующих VIP адресов" msgid "Selected Instances" msgstr "Выбранные инстансы" msgid "Send String" msgstr "Строка запроса" msgid "TCP" msgstr "TCP" msgid "Terminate" msgstr "Удалить" #, python-format msgid "Unable to get VIP for pool %(pool)s." msgstr "Невозможно получить VIP для пула %(pool)s." #, python-format msgid "Unable to get health monitors for pool %(pool)s." msgstr "Не удалось получить мониторы статуса для пула %(pool)s." #, python-format msgid "Unable to get members for pool %(pool)s." msgstr "Невозможно получить участников для пула %(pool)s." msgid "Unable to get pool detail." msgstr "Невозможно получить детали пула." #, python-format msgid "Unable to get subnet for pool %(pool)s." msgstr "Невозможно получить подсеть для пула %(pool)s." #, python-format msgid "Unable to launch %(count)s named \"%(name)s\"." msgstr "Не удалось запустить %(count)s \"%(name)s\"." #, python-format msgid "Unable to modify load balancer \"%s\"." msgstr "Не удалось изменить балансировщик нагрузки \"%s\"." #, python-format msgid "Unable to retrieve details for loadbalancer \"%s\"." msgstr "Не удалось получить информацию о балансировщике нагрузки\"%s\"." #, python-format msgid "Unable to retrieve load balancer details. %s" msgstr "Не удалось получить информацию о балансировщике нагрузки. %s" msgid "Unable to retrieve members list. Please try again later." msgstr "Не удалось получить список участников. Повторите попытку позже." msgid "Unable to retrieve pools list." msgstr "Не удалось получить список пулов." msgid "Unable to retrieve vips." msgstr "Невозможно получить список VIP" msgid "Update" msgstr "Обновить" #, python-format msgid "Updated load balancer \"%s\"." msgstr "Обновлён балансировщик \"%s\"." msgid "loadbalancer" msgstr "балансировщик нагрузки" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/ru/LC_MESSAGES/djangojs.po0000664000175100017510000007017015033037474026463 0ustar00mylesmyles# Aleksey Alekseenko <9118250541@mail.ru>, 2016. #zanata # Alexander , 2016. #zanata # Andrew , 2016. #zanata # Artem , 2016. #zanata # Artem , 2017. #zanata # Fedor Tarasenko , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard 1.0.1.dev55\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2017-02-03 18:54+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-02-03 08:56+0000\n" "Last-Translator: Fedor Tarasenko \n" "Language-Team: Russian\n" "Language: ru\n" "X-Generator: Zanata 3.7.3\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" #, python-format msgid "%(ip)s..." msgstr "%(ip)s..." msgid "" "Expected status codes:\n" " The expected HTTP status codes to get from a successful health check. Must " "be a single number,\n" " a comma separated list of numbers, or a range (two numbers separated by a " "hyphen)." msgstr "" "Ожидаемый статус-код:\n" " Ожидаемый HTTP статус-код при успешной проверке работоспособности. Должен " "быть одним \n" "числом, списком чисел разделённых запятой или диапозоном(два чиста " "разделённых дефисом)." msgid "" "HTTP method:\n" " The HTTP method used to perform the health check." msgstr "" "HTTP метод:\n" " HTTP метод используется для проверки работоспособности." msgid "" "IP address:\n" " If an IP address is provided it must be a well-formed IPv4 or IPv6 " "address. The system will\n" " attempt to assign the provided IP address to the load balancer. If an IP " "address is not provided\n" " then one will be allocated for you." msgstr "" "IP адрес:\n" " Если предоставляется IP адрес, то он должен быть в формате IPv4 или IPv6. " "Система попытается\n" " назначить предоставленный IP адрес балансировщику нагрузки. Если IP адресс " "не предоставлен,\n" "тогда он будет выделен вам. " msgid "" "IP address:\n" " The IP address of the member to receive traffic from the load balancer. " "Must be a well-formed\n" " IPv4 or IPv6 address." msgstr "" "IP адрес:\n" " IP адрес участника для получение даннх от балансировщика нагрузки. Должен " "быть в формате \n" " IPv4 или IPv6." msgid "" "Interval:\n" " The interval between health checks. Must be greater than or equal to the " "timeout." msgstr "" "Интервал:\n" " Интервал между проверками работоспособности. Должен быть не меньше времени " "ожидания." msgid "" "Method:\n" " The load balancer algorithm that distributes traffic to the pool members.\n" "
    \n" "
  • \n" " LEAST_CONNECTIONS: Allocates requests to the instance with the least " "number of active\n" " connections.\n" "
  • \n" "
  • \n" " ROUND_ROBIN: Rotates requests evenly between multiple instances.\n" "
  • \n" "
  • \n" " SOURCE_IP: Requests from a unique source IP address are consistently " "directed to the same instance.\n" "
  • \n" "
" msgstr "" "Алгоритм:\n" " Алгоритм балансировки, используемый для распределения трафика среди " "участников пула.\n" "
    \n" "
  • \n" " LEAST_CONNECTIONS: Направляет запросы инстансу с наименьшим " "количеством соединений.\n" "
  • \n" "
  • \n" " ROUND_ROBIN: Равномерно распределяет запросы между инстансами.\n" "
  • \n" "
  • \n" " SOURCE_IP: Запросы от одинаковых IP адресов последовательно " "направляются на один и тот же инстанс.\n" "
  • \n" "
" msgid "" "Port:\n" " The port on which the member listens for traffic. Must be a number from 1 " "to 65535." msgstr "" "Порт:\n" " Порт, через который участник пула ожидает трафик. Должен быть в диапазоне " "между 1 и 65535." msgid "" "Retries:\n" " The number of allowed connection failures before marking the member as " "inactive. Must be a\n" " number from 1 to 10." msgstr "" "Повторы:\n" " Количество допустимых ошибок соединения перед изменением состояния " "участника на неактивное. Значение должно\n" " быть в диапазоне между 1 и 10." msgid "" "Subnet:\n" " The network on which to allocate the load balancer's IP address." msgstr "" "Подсеть:\n" " Сеть в которой выделяется IP адрес балансировщику нагрузки." msgid "" "Subnet:\n" " The network which contains the IP address of the member." msgstr "" "Подсеть:\n" " Сеть содержащая IP адрес участников." msgid "" "Weight:\n" " The weight of a member determines the portion of requests or connections " "it services compared\n" " to the other members of the pool. A higher weight means it will receive " "more traffic. Must be\n" " a number from 1 to 256." msgstr "" "Вес:\n" " Вес участника определяет долю обслуживаемых запросов или соединений по " "отношению к другим участникам пула.\n" " Больший вес означает, что участник пула получит больше трафика. Должен быть " "в диапазоне между 1 и 256." msgid "A new health monitor is being created." msgstr "Новый монитор работоспособности создается." msgid "A new listener is being created." msgstr "Новый получатель запросов создается." msgid "A new load balancer is being created." msgstr "Новый балансировщик нагрузки создается." msgid "A new pool is being created." msgstr "Новый пул создается." msgid "" "A pool represents a group of members over which the load balancing will be " "applied." msgstr "" "Пул представляет собой группу участников, среди которых распределяется " "нагрузка." msgid "Actions" msgstr "Действия" msgid "Active" msgstr "Активный" msgid "Add" msgstr "Добавить" msgid "Add external member" msgstr "Добавить внешнего участника" msgid "Add members to the load balancer pool." msgstr "Добавить участников в пул балансировщика нагрузки." msgid "Add/Remove Pool Members" msgstr "Добавить/Удалить участников пула" msgid "Address" msgstr "Адрес" msgid "Admin State Up" msgstr "Административное состояние UP" msgid "Allocated Members" msgstr "Выделенные участники" msgid "An error occurred. Please try again later." msgstr "Произошла ошибка. Повторите попытку." msgid "Associate" msgstr "Назначить" msgid "Associate Floating IP" msgstr "Связать назначаемый IP" msgid "Associate Floating IP Address" msgstr "Привязать назначаемый IP адрес" msgid "Associating floating IP with load balancer." msgstr "Связывание назначаемого IP с балансировщиком нагрузки." msgid "Available Instances" msgstr "Доступные инстансы" msgid "Cancel" msgstr "Отмена" msgid "Certificate Name" msgstr "Имя сертификата" msgid "Confirm Delete Health Monitor" msgstr "Подтвердите Удаление Монитора Работоспособности" msgid "Confirm Delete Listeners" msgstr "Подтвердите удаление получателей" msgid "Confirm Delete Load Balancers" msgstr "Подтвердите Удаление Балансировщиков Нагрузки" msgid "Confirm Delete Pool" msgstr "Подтвердите удаление пула" msgid "Confirm Disassociate Floating IP Address" msgstr "Подтвердите отвязку назначаемых IP адресов" msgid "Connection Limit" msgstr "Лимит соединений" msgid "Create Health Monitor" msgstr "Создать Монитор Работоспособности." msgid "Create Listener" msgstr "Создать Получателя" msgid "Create Load Balancer" msgstr "Создать Балансировщик Нагрузки" msgid "Create Pool" msgstr "Создать Пул" msgid "Default Pool ID" msgstr "ИД Пула по умолчанию" msgid "Degraded" msgstr "Деградировавший" msgid "Delay" msgstr "Задержка" msgid "Delete Health Monitor" msgstr "Удалить Монитор Работоспособности" msgid "Delete Listener" msgstr "Удалить получателя" msgid "Delete Listeners" msgstr "Удалить Получателей" msgid "Delete Load Balancer" msgstr "Удалить Балансировщик Нагрузки" msgid "Delete Load Balancers" msgstr "Удалить Балансировщики Нагрузки" msgid "Delete Pool" msgstr "Удалить пул" #, python-format msgid "Deleted health monitor: %s." msgstr "Удаленный монитор работоспособности: %s." #, python-format msgid "Deleted listeners: %s." msgstr "Удаленные получатели: %s." #, python-format msgid "Deleted load balancers: %s." msgstr "Удаленные балансировщики нагрузки: %s." #, python-format msgid "Deleted pool: %s." msgstr "Удален пул: %s." msgid "Description" msgstr "Описание" msgid "Disassociate" msgstr "Снять назначение" msgid "Disassociate Floating IP" msgstr "Отвязать Назначаемый IP" msgid "Edit" msgstr "Редактировать" msgid "Error" msgstr "Ошибка" msgid "Expected Codes" msgstr "Ожидаемые коды" msgid "Expected status codes" msgstr "Ожидаемые статус-коды" msgid "Expiration Date" msgstr "Дата окончания действия" msgid "Floating IP Address" msgstr "Нефиксированный IP Адресс" msgid "" "Floating IP address or pool\n" " " msgstr "" "Назначаемый IP адрес или пул\n" " " msgid "Floating IP addresses" msgstr "Назначаемые IP-адреса" msgid "Floating IP pools" msgstr "Пул назначаемых IP адресов" msgid "HTTP Method" msgstr "Метод HTTP" msgid "HTTP method" msgstr "Метод HTTP" msgid "Health Monitor ID" msgstr "ИД Монитора Работоспособности" msgid "ID" msgstr "ID" msgid "IP Address" msgstr "IP адрес" msgid "" "IP Address\n" " 0\">\n" " \n" " \n" " Subnet\n" " 0\">\n" " \n" " \n" " Port\n" " 0\">\n" " \n" " Weight\n" " " msgstr "" "IP адрес\n" " 0\">\n" " \n" " \n" " Подсеть\n" " 0\">\n" " \n" " \n" " Порт\n" " 0\">\n" " \n" " Вес\n" " " #, python-format msgid "IP Addresses (%(count)s)" msgstr "IP адрес (%(count)s)" msgid "IP address" msgstr "IP адрес" msgid "" "If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL " "certificates must\n" " be selected. The first certificate will be the default." msgstr "" "Один или более SSL сертификат должны быть выбраны если слушатель использует " "TERMINATED_HTTPS протокол. Первый сертификат будет использоваться по " "умолчанию." msgid "" "Interval (sec)\n" " " msgstr "" "Интервал (сек)\n" " " msgid "Least Connections" msgstr "Меньше соединений" #, python-format msgid "Listener %(index)s" msgstr "Слушатель %(index)s" msgid "Listener 1" msgstr "Слушатель 1" msgid "Listener Details" msgstr "Информация о слушателе" msgid "Listener ID" msgstr "ИД получателя" msgid "Listeners" msgstr "Получатели" #, python-format msgid "Load Balancer %(index)s" msgstr "Балансировщика нагрузки %(index)s" msgid "Load Balancer Algorithm" msgstr "Алгоритм балансировки" msgid "Load Balancer Details" msgstr "Информация о балансировщике нагрузки" msgid "Load Balancer ID" msgstr "ИД балансировщика нагрузки" msgid "Load Balancers" msgstr "Балансировщики нагрузки" msgid "Loading" msgstr "Загрузка" msgid "Max Retries" msgstr "Максимальное количество повторных попыток" msgid "Member ID" msgstr "ИД Участника" msgid "Members" msgstr "Участники" msgid "" "Method\n" " " msgstr "" "Метод\n" " " msgid "Monitor ID" msgstr "ИД монитора" msgid "" "Monitor type\n" " " msgstr "" "Тип монитора\n" " " msgid "Name" msgstr "Имя" msgid "No available certificates" msgstr "Нет доступных сертификатов" msgid "No available instances" msgstr "Нет доступных инстансов" msgid "No items to display." msgstr "Нет элементов для отображения." msgid "No members have been allocated" msgstr "Участники не были выбраны" msgid "None" msgstr "Нет" msgid "Offline" msgstr "Вне сети" msgid "Online" msgstr "В сети" msgid "Operating Status" msgstr "Рабочий Статус" msgid "Overview" msgstr "Обзор" msgid "Pending Create" msgstr "Ожидает создание" msgid "Pending Delete" msgstr "Ожидает удаления" msgid "Pending Update" msgstr "Ожидает обновления" msgid "Pool 1" msgstr "Пул 1" msgid "Pool Details" msgstr "Информация о пуле" msgid "Pool ID" msgstr "ИД пула" msgid "Pool Members" msgstr "Участники пула" msgid "Port" msgstr "Порт" msgid "" "Port\n" " " msgstr "" "Порт\n" " " msgid "Port ID" msgstr "ID порта" msgid "Project ID" msgstr "ID проекта" msgid "Protocol" msgstr "Протокол" msgid "" "Protocol\n" " " msgstr "" "Протокол\n" " " msgid "Protocol Port" msgstr "Порт протокола" msgid "Provide the details for the health monitor." msgstr "Предоставить детали для монитора состояния." msgid "Provide the details for the listener." msgstr "Предоставить детали для слушателя." msgid "Provide the details for the load balancer." msgstr "Предоставить детали для балансировщика нагрузки." msgid "Provide the details for the pool." msgstr "Предоставить детали для пула." msgid "Provider" msgstr "Провайдер" msgid "Provisioning Status" msgstr "Статус развертывания" msgid "Remove" msgstr "Удалить" msgid "" "Retries\n" " " msgstr "" "Повторные попытки\n" " " msgid "Round Robin" msgstr "Циклический" msgid "SSL Certificates" msgstr "SSL сертификаты" msgid "" "Select a floating IP address to associate with the load balancer or a " "floating IP pool in which to allocate a new floating IP address." msgstr "" "Выберите назначаемый IP адрес для балансировщика нагрузки или пул " "назначаемых IP адресов для выделения нового назначаемого IP адреса." msgid "Select certificates from the available certificates below" msgstr "Выберите сертификаты из числа доступных указанных ниже" msgid "Select one or more SSL certificates for the listener." msgstr "Выберите один или более SSL сертификатов для службы отчётов." msgid "Session Persistence" msgstr "Постоянство сессии" msgid "Source IP" msgstr "IP-адрес источника" msgid "" "Subnet\n" " " msgstr "" "Подсеть\n" " " msgid "Subnet ID" msgstr "ID подсети" msgid "The IP address is not valid." msgstr "IP адрес не действителен." msgid "The URL path is not valid." msgstr "URL не является действительным." msgid "The expected status code is not valid." msgstr "Ожидаемый код состояния невалиден." #, python-format msgid "The following health monitor could not be deleted: %s." msgstr "Следующий монитор работоспособности не может быть удален: %s." #, python-format msgid "" "The following listeners could not be deleted, possibly due to existing " "pools: %s." msgstr "" "Следующие получатели не могут быть удалены, возможно из за существующих " "пулов: %s." #, python-format msgid "The following listeners will not be deleted due to existing pools: %s." msgstr "Следующие получатели не будут удалены из за существующих пулов: %s." #, python-format msgid "The following load balancers are pending and cannot be deleted: %s." msgstr "" "Следующие балансировщики нагрузки в состоянии ожидания и не могут быть " "удалены: %s." #, python-format msgid "" "The following load balancers could not be deleted, possibly due to existing " "listeners: %s." msgstr "" "Следующие балансировщики нагрузки не могут быть удалены, возможно из за " "существующих получателей: %s." #, python-format msgid "The following pool could not be deleted: %s." msgstr "Данный пул не может быть удален: %s." msgid "The health check interval must be greater than or equal to the timeout." msgstr "" "Интервал проверки работоспособности должен быть не меньше времени ожидания." msgid "The health monitor has been updated." msgstr "Монитор работоспособности был обновлен." msgid "The listener has been updated." msgstr "Получатель был обновлен." msgid "The load balancer has been updated." msgstr "Балансировщик нагрузки был обновлен." msgid "" "The load balancer occupies a neutron network port and has an IP address " "assigned from a subnet." msgstr "" "Балансировщик нагрузки занимает порт в сети Neutron и имеет IP адрес, " "выделенный из подсети" msgid "The max retry count must be a number between 1 and 10." msgstr "Количество попыток должно быть в диапазон между 1 и 10." msgid "The pool has been updated." msgstr "Пул был обновлен." msgid "The pool members have been updated." msgstr "Элементы пула были изменены." msgid "The port must be a number between 1 and 65535." msgstr "Значение для порта должно быть в диапозоне между 1 и 65535." msgid "" "The port must be unique among all listeners attached to this load balancer." msgstr "" "Порт должен быть уникален среди приемников, присоединенных к балансировщику " "нагрузки." msgid "The timeout must be a number greater than or equal to 0." msgstr "Значение таймаута должно быть больше или рано 0." msgid "The weight must be a number between 1 and 256." msgstr "Значение веса должно быть в диапозоне между 1 и 256." msgid "Timeout" msgstr "Таймаут" msgid "" "Timeout (sec)\n" " " msgstr "" "Таймаут (сек)\n" " " msgid "Type" msgstr "Тип" msgid "URL Path" msgstr "Путь URL" msgid "URL path" msgstr "Путь URL" msgid "Unable to create health monitor." msgstr "Не удалось создать монитор работоспособности." msgid "Unable to create listener." msgstr "Не удалось создать получателя." msgid "Unable to create load balancer." msgstr "Не удалось создать балансировщик нагрузки." msgid "Unable to create pool." msgstr "Не удалось создать пул." msgid "Unable to delete health monitor." msgstr "Не удалось удалить монитор работоспособности." msgid "Unable to delete listener." msgstr "Не удалось удалить получателя." msgid "Unable to delete load balancer." msgstr "Не удалось удалить балансировщик нагрузки." msgid "Unable to delete pool." msgstr "Не удалось удалить пул." #, python-format msgid "Unable to disassociate floating IP address from load balancer: %s." msgstr "" "Не удаётся отвязать назначаемый IP адрес от балансировщика нагрузки: %s." msgid "Unable to retrieve SSL certificates." msgstr "Не удалось получить SSL сертификаты." msgid "Unable to retrieve health monitor." msgstr "Не удалось получить монитор работоспособности." msgid "Unable to retrieve listener." msgstr "Не удалось получить получателя." msgid "Unable to retrieve listeners." msgstr "Не удалось получить получателей." msgid "Unable to retrieve load balancer." msgstr "Не удалось получить данные балансировщика нагрузки." msgid "Unable to retrieve load balancers." msgstr "Не удалось получить список балансировщиков нагрузки." msgid "Unable to retrieve member." msgstr "Не удалось получить участника." msgid "Unable to retrieve members." msgstr "Не удалось получить участников." msgid "Unable to retrieve pool." msgstr "Не удалось получить пул." msgid "Unable to retrieve secrets." msgstr "Невозможно получить секретные ключи." msgid "Unable to update health monitor." msgstr "Не удалось обновить монитор работоспособности." msgid "Unable to update listener." msgstr "Не удалось обновить получателя." msgid "Unable to update load balancer." msgstr "Не удалось обновить балансировщик нагрузки." msgid "Unable to update member list." msgstr "Не удалось обновить список участников." msgid "Unable to update member." msgstr "Не удалось обновить участника." msgid "Unable to update pool." msgstr "Не удалось обновить пул." msgid "Update" msgstr "Обновить" msgid "Update Health Monitor" msgstr "Обновить Монитор Работоспособности" msgid "Update Listener" msgstr "Обновить получатель" msgid "Update Load Balancer" msgstr "Обновить Балансировщик Нагрузки" msgid "Update Pool" msgstr "Обновить пул" msgid "Weight" msgstr "Вес" msgid "" "Weight\n" " " msgstr "" "Вес\n" " " #, python-format msgid "" "You are about to disassociate the floating IP address from load balancer \"%s" "\". Please confirm." msgstr "" "Вы собираетесь отвязать назначаемые IP адреса от балансировщика нагрузки \"%s" "\". Пожалуйста подтвердите." #, python-format msgid "" "You have selected \"%s\". Please confirm your selection. Deleted health " "monitors are not recoverable." msgstr "" "Вы выбрали \"%s\". Пожалуйста подтвердите ваш выбор. Удаление монитора " "работоспособности необратимо." #, python-format msgid "" "You have selected \"%s\". Please confirm your selection. Deleted listeners " "are not recoverable." msgstr "" "Вы выбрали \"%s\". Пожалуйста подтвердите ваш выбор. Удаление получателей " "необратимо." #, python-format msgid "" "You have selected \"%s\". Please confirm your selection. Deleted load " "balancers are not recoverable." msgstr "" "Вы выбрали \"%s\". Пожалуйста подтвердите ваш выбор. Удаление " "балансировщиков нагрузки необратимо." #, python-format msgid "" "You have selected \"%s\". Please confirm your selection. Deleted pools are " "not recoverable." msgstr "" "Вы выбрали \"%s\". Пожалуйста подтвердите ваш выбор. Удаление пулов " "необратимо." ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4541008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/zh_Hans/0000775000175100017510000000000015033037476023500 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/zh_Hans/LC_MESSAGES/0000775000175100017510000000000015033037476025265 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/zh_Hans/LC_MESSAGES/django.po0000664000175100017510000000113215033037474027062 0ustar00mylesmyles# Jacky Hu , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2021-02-28 17:23+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-06-01 02:50+0000\n" "Last-Translator: Jacky Hu \n" "Language-Team: Chinese (China)\n" "Language: zh_CN\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "Load Balancers" msgstr "负载均衡器" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/zh_Hans/LC_MESSAGES/djangojs.po0000664000175100017510000011170315033037474027425 0ustar00mylesmyles# Jacky Hu , 2018. #zanata # Tony , 2019. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2022-08-16 20:34+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2019-03-21 01:01+0000\n" "Last-Translator: Tony \n" "Language-Team: Chinese (China)\n" "Language: zh_CN\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" #, python-format msgid "%(ip)s..." msgstr "%(ip)s..." msgid "A new health monitor is being created." msgstr "一个新的健康监控器正在创建。" msgid "A new l7 policy is being created." msgstr "一个新的七层策略正在被创建" msgid "A new listener is being created." msgstr "一个新的监听器正在创建。" msgid "A new load balancer is being created." msgstr "一个新的负载均衡器正在创建。" msgid "A new pool is being created." msgstr "一个新的资源池正在创建。" msgid "" "A pool represents a group of members over which the load balancing will be " "applied." msgstr "资源池代表提供负载均衡器的一组成员。" msgid "APP_COOKIE: Session persistence based on application cookie." msgstr "APP_COOKIE:基于应用 COOKIE 的会话持久化。" msgid "Action" msgstr "行为" msgid "Action:" msgstr "行为:" msgid "Active" msgstr "运行中" msgid "Add" msgstr "添加" msgid "Add external member" msgstr "添加外部成员" msgid "Add members to the load balancer pool." msgstr "为负载均衡池添加成员。" msgid "Add/Remove Members" msgstr "添加/移除成员" msgid "Add/Remove Pool Members" msgstr "添加/移除资源池成员" msgid "" "Additional headers insertion into HTTP header,\n" " only \"X-Forwarded-For\", \"X-Forwarded-Port\" and \"X-Forwarded-Proto\" " "are supported." msgstr "" "插入到 HTTP 头部的额外报头。\n" "仅支持 \"X-Forwarded-For\"、\"X-Forwarded-Port\" 和 \"X-Forwarded-Proto\"。" msgid "Admin State Up" msgstr "管理状态:启动" msgid "Algorithm" msgstr "算法" msgid "Algorithm:" msgstr "算法:" msgid "Allocated Members" msgstr "分配成员" msgid "" "An L7 Policy is a collection of L7 rules associated with a Listener, and " "which may also have an association to a back-end pool" msgstr "一个七层策略是关联于监听器的七层规则的集,监听器可能有一个关联的资源池" msgid "" "An L7 Rule is a single, simple logical test which returns either true or\n" "false." msgstr "一个七层规则是返回是或否的单一简单逻辑测试" msgid "" "An alternate IP address used for health monitoring a backend member.\n" " Default is null which monitors the member address." msgstr "" "用于后端成员健康监控的 IP 地址。\n" "默认是空时监测该成员地址。" msgid "" "An alternate protocol port used for health monitoring a backend member.\n" " Default is null which monitors the member protocol port." msgstr "" "用于后端成员健康监控的协议端口。\n" "默认是空时监测该成员协议端口。" msgid "An error occurred. Please try again later." msgstr "发生错误,请稍后重试。" msgid "Associate" msgstr "关联" msgid "Associate Floating IP" msgstr "关联浮动 IP" msgid "Associate Floating IP Address" msgstr "关联浮动 IP 地址" msgid "Associating floating IP with load balancer." msgstr "为负载均衡器关联浮动 IP。" msgid "Available Instances" msgstr "可用实例" msgid "Backend member connection timeout in milliseconds. Default: 5000." msgstr "后端成员连接超时时限,单位是毫秒,默认值:5000。" msgid "Backend member inactivity timeout in milliseconds. Default: 50000." msgstr "后端成员闲置超时时限,单位是毫秒,默认值:50000。" msgid "Backup" msgstr "备份" msgid "Backup:" msgstr "备份:" msgid "CIDR" msgstr "CIDR" msgid "CONTAINS: String contains." msgstr "包含:字符串包含。" msgid "" "COOKIE: The rule looks for a cookie named by the key parameter and\n" " compares it against the value parameter in the rule." msgstr "COOKIE:该规则查找以键参数命名的 COOKIE 并将其与值参数相比较。" msgid "Cancel" msgstr "取消" msgid "Certificate Name" msgstr "证书名称" msgid "Client Data Timeout" msgstr "客户数据超时时限" msgid "Client Data Timeout:" msgstr "客户数据超时时限:" msgid "Compare Type" msgstr "比较类型" msgid "Compare Type:" msgstr "比较类型:" msgid "Confirm Delete Health Monitor" msgid_plural "Confirm Delete Health Monitors" msgstr[0] "确认删除健康监控器" msgid "Confirm Delete L7 Policy" msgid_plural "Confirm Delete L7 Policies" msgstr[0] "确认删除七层策略" msgid "Confirm Delete L7 Rule" msgid_plural "Confirm Delete L7 Rules" msgstr[0] "确认删除七层规则" msgid "Confirm Delete Listener" msgid_plural "Confirm Delete Listeners" msgstr[0] "确认删除监听器" msgid "Confirm Delete Load Balancer" msgid_plural "Confirm Delete Load Balancers" msgstr[0] "确认删除负载均衡器" msgid "Confirm Delete Member" msgid_plural "Confirm Delete Members" msgstr[0] "确认删除成员" msgid "Confirm Delete Pool" msgid_plural "Confirm Delete Pools" msgstr[0] "确认删除资源池" msgid "Confirm Disassociate Floating IP Address" msgstr "确认解除关联浮动 IP 地址。" msgid "Connection Limit" msgstr "连接限制" msgid "Connection Limit:" msgstr "连接限制:" msgid "Contains" msgstr "包含" msgid "Cookie" msgstr "Cookie" msgid "Cookie Name" msgstr "Cookie 名称" msgid "Create Health Monitor" msgstr "创建健康监控器。" msgid "Create L7 Policy" msgstr "创建七层策略" msgid "Create L7 Rule" msgstr "创建七层规则" msgid "Create Listener" msgstr "创建监控器" msgid "Create Load Balancer" msgstr "创建负载均衡器" msgid "Create Pool" msgstr "创建资源池" msgid "Created At" msgstr "创建于" msgid "Default Pool ID" msgstr "默认资源池 ID" msgid "Default Pool ID:" msgstr "默认资源池 ID:" msgid "Default TLS Container Ref" msgstr "默认 TLS 容器编号" msgid "Degraded" msgstr "衰退" msgid "Delay" msgstr "延迟" msgid "Delay (sec)" msgstr "延迟(秒)" msgid "Delay:" msgstr "延迟:" msgid "Delete Health Monitor" msgid_plural "Delete Health Monitors" msgstr[0] "删除健康监控" msgid "Delete Health Monitors" msgstr "删除健康监控" msgid "Delete L7 Policies" msgstr "删除七层策略" msgid "Delete L7 Policy" msgid_plural "Delete L7 Policies" msgstr[0] "删除七层策略" msgid "Delete L7 Rule" msgid_plural "Delete L7 Rules" msgstr[0] "删除七层规则" msgid "Delete L7 Rules" msgstr "删除七层规则" msgid "Delete Listener" msgid_plural "Delete Listeners" msgstr[0] "删除监控器" msgid "Delete Listeners" msgstr "删除监控器" msgid "Delete Load Balancer" msgid_plural "Delete Load Balancers" msgstr[0] "删除负载均衡器" msgid "Delete Load Balancers" msgstr "删除负载均衡器" msgid "Delete Member" msgid_plural "Delete Members" msgstr[0] "删除成员" msgid "Delete Members" msgstr "删除成员" msgid "Delete Pool" msgid_plural "Delete Pools" msgstr[0] "删除资源池" msgid "Delete Pools" msgstr "删除资源池" #, python-format msgid "Deleted Health Monitor: %s." msgid_plural "Deleted Health Monitors: %s." msgstr[0] "删除的健康监控器:%s。" #, python-format msgid "Deleted L7 Policy: %s." msgid_plural "Deleted L7 Policies: %s." msgstr[0] "删除的七层策略:%s。" #, python-format msgid "Deleted L7 Rule: %s." msgid_plural "Deleted L7 Rules: %s." msgstr[0] "删除的七层规则:%s。" #, python-format msgid "Deleted Listener: %s." msgid_plural "Deleted Listeners: %s." msgstr[0] "删除的监听器:%s。" #, python-format msgid "Deleted Load Balancer: %s." msgid_plural "Deleted Load Balancers: %s." msgstr[0] "删除的负载均衡器:%s。" #, python-format msgid "Deleted Member: %s." msgid_plural "Deleted Members: %s." msgstr[0] "删除的成员:%s。" #, python-format msgid "Deleted Pool: %s." msgid_plural "Deleted Pools: %s." msgstr[0] "删除的资源池:%s。" msgid "Description" msgstr "描述" msgid "Disassociate" msgstr "取消关联" msgid "Disassociate Floating IP" msgstr "解除关联浮动 IP" #, python-format msgid "Disassociated floating IP address from load balancer: %s." msgstr "已从负载均衡器取解除浮动IP关联:%s。" msgid "ENDS_WITH: String ends with." msgstr "ENDS_WITH:字符串后缀。" msgid "EQUAL_TO: String is equal to." msgstr "EQUAL_TO:字符串相同。" msgid "" "Each port that listens for traffic on a particular load balancer is " "configured separately and\n" " tied to the load balancer. Multiple listeners can be associated with the " "same load balancer but\n" " each must use a unique port." msgstr "" "负载均衡器中的每一个监听的端口独立地配置并与负载均衡器关联。\n" "多个监听器可以关联到同一个负载均衡器上,\n" "但每个都必须使用唯一的端口。" msgid "Edit Health Monitor" msgstr "编辑健康监控" msgid "Edit L7 Policy" msgstr "编辑七层策略" msgid "Edit L7 Rule" msgstr "编辑七层规则" msgid "Edit Listener" msgstr "编辑监控器" msgid "Edit Load Balancer" msgstr "编辑负载均衡器" msgid "Edit Member" msgstr "编辑成员" msgid "Edit Pool" msgstr "编辑资源池" msgid "Ends With" msgstr "结束于" msgid "Equal To" msgstr "等于" msgid "Error" msgstr "错误" msgid "Expected Codes" msgstr "预期的状态码" msgid "Expected Codes:" msgstr "预期的状态码:" msgid "Expiration Date" msgstr "截止日期" msgid "" "FILE_TYPE: The rule compares the last portion of the URI against\n" " the value parameter in the rule. (eg. \"txt\", \"jpg\", etc.)" msgstr "FILE_TYPE:该规则将 URI 的后缀与值参数相比较。(例如:“txt”,“jpg”。)" msgid "File Type" msgstr "文件类型" msgid "Flavor" msgstr "类型" msgid "Flavor Description" msgstr "实例类型描述" msgid "Flavor ID" msgstr "实例类型 ID" msgid "Floating IP" msgstr "浮动 IP" msgid "Floating IP address or pool" msgstr "浮动 IP 地址或浮动 IP 地址池" msgid "Floating IP addresses" msgstr "浮动 IP 地址" msgid "Floating IP pools" msgstr "浮动 IP 资源池" msgid "Frontend client inactivity timeout in milliseconds. Default: 50000." msgstr "前端客户闲置超时时限,单位是毫秒,默认值:50000。" msgid "" "HEADER: The rule looks for a header defined in the key parameter\n" " and compares it against the value parameter in the rule." msgstr "HEADER:该规则查找以键参数命名的报头并将其与值参数相比较。" msgid "" "HOST_NAME: The rule does a comparison between the HTTP/1.1\n" " hostname in the request against the value parameter in the rule." msgstr "HOST_NAME:该规则将请求中的 HTTP/1.1 主机名与值参数相比较。" msgid "HTTP Method" msgstr "HTTP 方法" msgid "HTTP Method:" msgstr "HTTP 方法:" msgid "HTTP_COOKIE: Session persistence based on http cookie." msgstr "HTTP_COOKIE:基于 HTTP COOKIE 的会话持久化。" msgid "Header" msgstr "报头" msgid "Health Monitor" msgstr "健康监控" msgid "Health Monitor ID" msgstr "健康监控器 ID" msgid "Health Monitors" msgstr "健康监控" msgid "Host Name" msgstr "主机名" msgid "ID" msgstr "ID" msgid "IP Address" msgstr "IP 地址" #, python-format msgid "IP Addresses (%(count)s)" msgstr "IP 地址(%(count)s)" msgid "IP address" msgstr "IP 地址" msgid "IP address:" msgstr "IP 地址:" msgid "" "If an IP address is provided it must be a well-formed IPv4 or IPv6 address. " "The system will\n" " attempt to assign the provided IP address to the load balancer. If an IP " "address is not provided\n" " then one will be allocated for you." msgstr "" "IP地址必须为格式良好的 IPv4 或 IPv6 地址。\n" "系统尝试为负载均衡器分配提供的 IP 地址。\n" "如果没有提供 IP 地址,则需要你手动分配一个 IP。" msgid "" "If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL " "certificates must\n" " be selected. The first certificate will be the default." msgstr "" "如果监听器使用 TERMINATED_HTTPS 协议,则必须选择一个或多个 SSL 证书。\n" "默认选择第一个。" msgid "Inactive" msgstr "闲置" msgid "Insert Headers" msgstr "插入报头" msgid "Insert Headers:" msgstr "插入报头:" msgid "Invert" msgstr "反转" msgid "Invert:" msgstr "反转:" msgid "" "Is the member a backup? Backup members only receive traffic when all\n" " non-backup members are down." msgstr "该成员是否为备份?备份成员仅当所有非备份成员不可用时才接收通信。" msgid "Key" msgstr "键" msgid "Key Manager API Guide: Creating a Certificate Container" msgstr "Key Manager API 指南:创建证书容器" msgid "Key Manager Service Command-Line Client" msgstr "Key Manager 服务命令行客户端" msgid "Key:" msgstr "键:" msgid "L7 Policies" msgstr "七层策略" msgid "L7 Policy" msgstr "七层策略" msgid "L7 Policy Details" msgstr "七层策略详情" msgid "L7 Rule" msgstr "七层规则" msgid "L7 Rule Details" msgstr "七层规则详情" msgid "L7 Rules" msgstr "七层规则" msgid "" "LEAST_CONNECTIONS: Allocates requests to the instance with the least number " "of active\n" " connections." msgstr "LEAST_CONNECTIONS:分发至最少活动连接次数的实例。" msgid "Least Connections" msgstr "最少连接数" msgid "Listener" msgstr "监控器" msgid "Listener Details" msgstr "监听器详情" msgid "Listener ID" msgstr "监听器ID" msgid "Listeners" msgstr "监控器" msgid "Load Balancer" msgstr "负载均衡器" msgid "Load Balancer Details" msgstr "负载均衡器详情" msgid "Load Balancers" msgstr "负载均衡器" msgid "Loading" msgstr "加载中" msgid "Max Retries" msgstr "最大尝试次数" msgid "Max Retries Down" msgstr "最大失败尝试次数" msgid "Max Retries Down:" msgstr "最大失败重试次数:" msgid "Max Retries:" msgstr "最大重试次数:" msgid "Member" msgstr "成员" msgid "Member Connect Timeout" msgstr "成员连接超时时限" msgid "Member Connect Timeout:" msgstr "成员连接超时时限:" msgid "Member Data Timeout" msgstr "成员数据超时时限" msgid "Member Data Timeout:" msgstr "成员数据超时时限:" msgid "Members" msgstr "成员" msgid "" "Members are the actual IP addresses that will receive traffic from the load " "balancer. Each\n" " member must have a unique combination of IP address and port." msgstr "" "成员是在负载均衡器中通信的实际 IP 地址。\n" "每个成员必须有一个唯一关联的 IP 地址和端口。" msgid "Monitor Address" msgstr "健康监听器地址" msgid "Monitor Address:" msgstr "健康监控器地址:" msgid "Monitor Details" msgstr "健康监控器详情" msgid "Monitor Port" msgstr "健康监听器端口" msgid "Monitor Port:" msgstr "健康监控器端口:" msgid "Name" msgstr "名称" msgid "Network" msgstr "网络" msgid "Network ID" msgstr "网络 ID" msgid "No" msgstr "否" msgid "No Monitor" msgstr "无健康监控" msgid "No available certificates" msgstr "无可用证书" msgid "No available instances" msgstr "无可用实例" msgid "No items to display." msgstr "没有要显示的项目。" msgid "No matching options" msgstr "没有匹配的选项" msgid "No members have been allocated" msgstr "没有成员已分配" msgid "None" msgstr "无" msgid "Offline" msgstr "离线" msgid "Online" msgstr "在线" msgid "Operating Status" msgstr "操作状态" msgid "Overview" msgstr "概览" msgid "" "PATH: The rule compares the path portion of the HTTP URI against\n" " the value parameter in the rule." msgstr "PATH:该规则将 HTTP URI 的路径部分与值参数相比较。" msgid "Path" msgstr "路径" msgid "Pending Create" msgstr "暂挂创建" msgid "Pending Delete" msgstr "暂挂删除" msgid "Pending Update" msgstr "暂挂更新" msgid "Please Wait" msgstr "请等待" msgid "Pool" msgstr "资源池" msgid "Pool Details" msgstr "资源池详情" msgid "Pool Members" msgstr "资源池成员" msgid "Pool member has been updated." msgstr "资源池成员已更新" msgid "Pools" msgstr "资源池" msgid "Port" msgstr "端口" msgid "Port ID" msgstr "端口 ID" msgid "Port:" msgstr "端口:" msgid "Position" msgstr "位置" msgid "Position:" msgstr "位置:" msgid "Project" msgstr "项目" msgid "Project ID" msgstr "项目 ID" msgid "Protocol" msgstr "协议" msgid "Protocol Port" msgstr "协议端口" msgid "Protocol:" msgstr "协议:" msgid "Provide the details for the health monitor." msgstr "为健康监控提供详情。" msgid "Provide the details for the l7 policy." msgstr "提供七层策略的详情。" msgid "Provide the details for the l7 rule." msgstr "提供七层规则的详情。" msgid "Provide the details for the listener." msgstr "为监听器提供详情。" msgid "Provide the details for the load balancer." msgstr "为负载均衡器提供详情。" msgid "Provide the details for the member." msgstr "为成员提供详情。" msgid "Provide the details for the pool." msgstr "为资源池提供详情。" msgid "Provider" msgstr "提供者" msgid "Provisioning Status" msgstr "配置状态" msgid "" "REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated " "with the L7 policy." msgstr "REDIRECT_TO_POOL:请求被转发到该七层策略关联的资源池。" msgid "" "REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in " "the redirect_url parameter." msgstr "" "REDIRECT_TO_URL:请求被作为一个 HTTP 重定向发送到 redirect_url 参数里定义的 " "URL。" msgid "REGEX: Perl type regular expression matching." msgstr "REGEX:Perl 正则表达式匹配。" msgid "" "REJECT: The request is denied with an appropriate response code, and not " "forwarded on to any back-end pool." msgstr "REJECT:请求被拒绝并返回合适的状态码,并不被转发给任何资源池" msgid "ROUND_ROBIN: Rotates requests evenly between multiple instances." msgstr "ROUND_ROBIN:在多个实例之间轮询分发。" msgid "Redirect Pool ID" msgstr "重定向资源池 ID" msgid "Redirect Pool ID:" msgstr "重定向资源池 ID:" msgid "Redirect URL" msgstr "重定向 URL" msgid "Redirect URL:" msgstr "重定向 URL:" msgid "Redirect to Pool" msgstr "重定向到资源池" msgid "Redirect to URL" msgstr "重定向到 URL" msgid "Regex" msgstr "正则表达式" msgid "Reject" msgstr "拒绝" msgid "Remove" msgstr "移除" msgid "" "Requests matching this policy will be redirected to the pool with this ID. " "Only valid if action is REDIRECT_TO_POOL." msgstr "" "与该策略相匹配的请求将被重定向到由 ID 指定的资源池。仅当行为是 " "REDIRECT_TO_POOL 时有效。" msgid "" "Requests matching this policy will be redirected to this URL. Only valid if " "action is REDIRECT_TO_URL." msgstr "" "与该策略相匹配的请求将被重定向指定的 URL。仅当行为是 REDIRECT_TO_URL 时有效。" msgid "Round Robin" msgstr "轮询" msgid "Rules" msgstr "规则" msgid "SNI Container Refs" msgstr "SNI 容器编号" msgid "" "SOURCE_IP: Requests from a unique source IP address are consistently " "directed to the same instance." msgstr "SOURCE_IP:来自相同源IP地址的请求连续的发送到同一实例。" msgid "SOURCE_IP: Session persistence based on source ip." msgstr "SOURCE_IP:基于源 IP 地址的会话持久化。" msgid "SSL Certificates" msgstr "SSL 证书" msgid "STARTS_WITH: String starts with." msgstr "STARTS_WITH:字符串前缀。" msgid "" "Select a floating IP address to associate with the load balancer or a " "floating IP pool in which to allocate a new floating IP address." msgstr "" "选择一个浮动 IP 地址关联一个负载均衡器或为浮动 IP 池分配一个新的浮动 IP 地址" "池。" msgid "Select certificates from the available certificates below" msgstr "从下面可选的证书中选择证书" msgid "Select one or more SSL certificates for the listener." msgstr "为监听器选择一个或多个 SSL 证书。" msgid "Session Persistence" msgstr "会话持久化" msgid "Session Persistence:" msgstr "会话持久化:" msgid "Source IP" msgstr "源IP" msgid "Starts With" msgstr "开始于" msgid "Subnet" msgstr "子网" msgid "Subnet ID" msgstr "子网 ID" msgid "Subnet:" msgstr "子网:" msgid "TCP Inspect Timeout" msgstr "TCP 监测超时时限" msgid "TCP Inspect Timeout:" msgstr "TCP 监测超时时限:" msgid "" "The Available Instances table contains existing compute instances that can " "be added as members\n" " of the pool. Use the \"Add external member\" button to add a member not " "found in the Available\n" " Instances table." msgstr "" "可用实例表显示了存在的可以添加为资源池成员的计算实例。\n" "使用“添加外部成员”按钮可以添加在可用实例表中找不到的成员。" msgid "The HTTP method used to perform the health check." msgstr "用来进行健康检查的 HTTP 请求方式。" msgid "The ID of the pool used by the listener if no L7 policies match." msgstr "无七层策略匹配时用于该监听器的资源池 ID。" msgid "The IP address is not valid." msgstr "IP 地址无效。" msgid "" "The IP address of the member to receive traffic from the load balancer. Must " "be a well-formed\n" " IPv4 or IPv6 address." msgstr "" "用于从负载均衡器中接收消息成员的 IP 地址。\n" "必须使用格式良好的 IPv4 或 IPv6 地址。" msgid "" "The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL." msgstr "七层策略行为。REJECT,REDIRECT_TO_URL,REDIRECT_TO_POOL 其中之一" msgid "The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH." msgstr "七层规则类型。COOKIE,FILE_TYPE,HEADER,HOST_NAME,PATH 之中之一。" msgid "The URL path is not valid." msgstr "URL 路径无效。" msgid "" "The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, or STARTS_WITH." msgstr "" "七层规则的比较类型。CONTAINS,ENDS_WITH,EQUAL_TO,REGEX,STARTS_WITH 其中之" "一。" msgid "The connection limit must be a number greater than or equal to -1." msgstr "连接限制必须是大于或等于 -1 的整数。" msgid "" "The expected HTTP status codes to get from a successful health check. Must " "be a single number,\n" " a comma separated list of numbers, or a range (two numbers separated by a " "hyphen)." msgstr "" "健康检查成功返回的期望 HTTP 状态码。\n" "必须为单个数字,逗号分隔的一组数字或一个范围(用连接符分隔的两个数字)。" msgid "The expected status code is not valid." msgstr "期望状态码无效。" msgid "The health check interval must be greater than or equal to the timeout." msgstr "健康检查间隔必须大于或等于超时时限。" msgid "The health monitor has been updated." msgstr "健康监控器已经更新。" msgid "" "The health monitor is used to determine the health of your pool members. " "Health checks\n" " routinely run against each member within the pool and the result of the " "health check is used\n" " to determine if the member receives new connections. Each pool can only " "have one health\n" " monitor." msgstr "" "健康监控用来确定你的资源池成员的健康状况。\n" "健康检查通常在资源池中与每个成员隔离运行,健康检查的结果通过成员接收到新的连" "接来确定。\n" "每个资源池只能有一个健康监控。" msgid "" "The interval between health checks. Must be greater than or equal to the " "timeout." msgstr "健康检查之间时间间隔,必须大于或等于超时时限。" msgid "" "The key to use for the comparison. For example, the name of the cookie\n" " to evaluate." msgstr "用于比较的键。例如 COOKIE 的名字。" msgid "The l7policy has been updated." msgstr "七层策略已更新" msgid "The l7rule has been updated." msgstr "七层规则已更新" msgid "The listener has been updated." msgstr "监听器已更新。" msgid "" "The load balancer algorithm that distributes traffic to the pool members." msgstr "用于分发消息给资源池成员的负载均衡算法。" msgid "The load balancer has been updated." msgstr "负载均衡器已更新。" msgid "" "The load balancer occupies a neutron network port and has an IP address " "assigned from a subnet." msgstr "负载均衡器占用一个 neutron 网络端口和一个子网分配的 IP 地址。" msgid "The max retry count must be a number between 1 and 10." msgstr "健康检查间隔必须大于或等于超时时限。" msgid "The max retry down count must be a number between 1 and 10." msgstr "最大失败尝试次数必须是 1 至 10 之间的整数。" msgid "" "The maximum number of connections permitted for this listener.\n" " Default value is -1 which represents infinite connections." msgstr "该监听器允许的最大连接数。默认值 -1 表示无限制。" msgid "The monitor address must be a valid IP address." msgstr "健康监听器地址必须是有效的 IP 地址。" msgid "The monitor port must be a number between 1 and 65535." msgstr "健康监听器端口必须是 1 至 65535 的整数" msgid "The network on which to allocate the load balancer's IP address." msgstr "给分配负载均衡器 IP 地址的网络。" msgid "The network which contains the IP address of the member." msgstr "关联成员 IP 地址的网络。" msgid "" "The number of allowed connection failures before marking the member as " "error. Must be a\n" " number from 1 to 10. The default is 3." msgstr "" "在将成员标记为错误之前,允许连接失败的次数。\n" "必须是 1 至 10 之间的整数。默认值是 3。" msgid "" "The number of allowed connection failures before marking the member as " "inactive. Must be a\n" " number from 1 to 10." msgstr "" "在将成员标记为未活动状态之前,允许连接失败的次数。\n" "必须是 1 至 10 之间的整数。" msgid "The pool has been updated." msgstr "资源池已更新。" msgid "The pool members have been updated." msgstr "资源池成员已更新" msgid "The port must be a number between 1 and 65535." msgstr "端口必须是 1 至 65536 之间的整数。" msgid "" "The port must be unique among all listeners attached to this load balancer." msgstr "负载均衡器上的所有监听器的端口号必须唯一。" msgid "" "The port on which the front end listens. Must be an integer from 1 to 65535." msgstr "用来通信的成员监听端口。必须是 1 至 65536 之间的整数。" msgid "" "The port on which the member listens for traffic. Must be a number from 1 to " "65535." msgstr "用来通信的成员监听端口。必须是 1 至 65536 之间的整数。" msgid "The position must be a number between 1 and 2147483647." msgstr "位置必须是一个 1 至 2147483647 的整数。" msgid "The position of this policy on the listener. Positions start at 1." msgstr "该策略在监听器里的位置。位置从一开始。" msgid "" "The protocol for which the front end listens. The TERMINATED_HTTPS protocol " "is only available if\n" " the key-manager service is enabled and you have authority to list " "certificate containers and\n" " secrets." msgstr "" "监听器之间通信的协议。\n" "TERMINATED_HTTPS 协议只有在 key-manager 服务可用\n" "并且你有权限查询证书容器和密钥的情况下才有用。" msgid "The redirect url must be a valid http or https url." msgstr "重定向 URL 必须是一个有效的 HTTP 或 HTTPS URL" msgid "" "The target of the health check HTTP request to the member. Must be a valid " "URL path." msgstr "成员发送健康检查 HTTP 请求的目标地址,必须为合法的 URL 路径。" msgid "" "The time after which a health check times out. Must be a number greater than " "or equal to 0\n" " and less than or equal to the interval." msgstr "" "健康检查请求超时的时间。\n" "必须为大于或等于 0 的整数,并小于或等于间隔时间。" msgid "The timeout must be a number between 0 and 31536000000." msgstr "超时时限必须是 0 至 31536000000 的整数。" msgid "The timeout must be a number greater than or equal to 0." msgstr "超时时限必须是一个大于等于 0 的整数。" msgid "" "The type of session persistence for distributing traffic to the pool members." msgstr "用于为资源池成员分发消息的会话持久化类型。" msgid "" "The value to use for the comparison. For example, the file type to compare." msgstr "用于比较的值。例如要比较的文件类型。" msgid "" "Time, in milliseconds, to wait for additional TCP packets for content\n" " inspection. Default: 0." msgstr "等待额外 TCP 内容监测包的超时时限,单位是毫秒,默认值:0。" msgid "Timeout" msgstr "超时时限" msgid "Timeout (sec)" msgstr "超时时限(秒)" msgid "Timeout:" msgstr "超时时限:" msgid "Type" msgstr "类型" msgid "Type:" msgstr "类型:" msgid "URL Path" msgstr "URL 路径" msgid "URL Path:" msgstr "URL 路径:" msgid "Unable to create flavor profile." msgstr "无法创建实例类型配置集。" msgid "Unable to create flavor." msgstr "无法创建实例类型。" msgid "Unable to create health monitor." msgstr "无法创建健康监控。" msgid "Unable to create l7 policy." msgstr "无法创建七层策略。" msgid "Unable to create l7 rule." msgstr "无法创建七层规则。" msgid "Unable to create listener." msgstr "无法创建监听器。" msgid "Unable to create load balancer." msgstr "无法创建负载均衡器。" msgid "Unable to create pool." msgstr "无法创建资源池。" #, python-format msgid "Unable to delete Health Monitor: %s." msgid_plural "Unable to delete Health Monitors: %s." msgstr[0] "无法删除健康监控:%s。" #, python-format msgid "Unable to delete L7 Policy: %s." msgid_plural "Unable to delete L7 Policies: %s." msgstr[0] "无法删除七层策略:%s。" #, python-format msgid "Unable to delete L7 Rule: %s." msgid_plural "Unable to delete L7 Rules: %s." msgstr[0] "无法删除七层规则:%s。" #, python-format msgid "Unable to delete Listener: %s." msgid_plural "Unable to delete Listeners: %s." msgstr[0] "无法删除监听器:%s。" #, python-format msgid "Unable to delete Load Balancer: %s." msgid_plural "Unable to delete Load Balancers: %s." msgstr[0] "无法删除负载均衡器:%s。" #, python-format msgid "Unable to delete Member: %s." msgid_plural "Unable to delete Members: %s." msgstr[0] "无法删除成员:%s。" #, python-format msgid "Unable to delete Pool: %s." msgid_plural "Unable to delete Pools: %s." msgstr[0] "无法删除资源池:%s。" msgid "Unable to delete flavor profile." msgstr "无法删除实例类型配置集。" msgid "Unable to delete flavor." msgstr "无法删除实例类型。" msgid "Unable to delete health monitor." msgstr "无法删除健康监控。" msgid "Unable to delete l7 policy." msgstr "无法删除七层策略。" msgid "Unable to delete l7 rule." msgstr "无法删除七层规则。" msgid "Unable to delete listener." msgstr "无法删除监听器。" msgid "Unable to delete load balancer." msgstr "无法删除负载均衡器。" msgid "Unable to delete member." msgstr "无法删除成员。" msgid "Unable to delete pool." msgstr "无法删除资源池。" #, python-format msgid "Unable to disassociate floating IP address from load balancer: %s." msgstr "无法从负载均衡器解除浮动IP地址关联:%s。" msgid "Unable to retrieve SSL certificates." msgstr "不能获取 SSL 证书。" msgid "Unable to retrieve flavor profile." msgstr "无法获取实例类型配置集。" msgid "Unable to retrieve flavor profiles." msgstr "无法获取实例类型配置集。" msgid "Unable to retrieve flavor." msgstr "无法获取实例类型。" msgid "Unable to retrieve flavors." msgstr "无法获取实例类型。" msgid "Unable to retrieve health monitor." msgstr "无法获取健康监控。" msgid "Unable to retrieve health monitors." msgstr "无法获取健康监控。" msgid "Unable to retrieve l7 policies." msgstr "无法获取七层策略。" msgid "Unable to retrieve l7 policy." msgstr "无法获取七层策略。" msgid "Unable to retrieve l7 rule." msgstr "无法获取七层规则。" msgid "Unable to retrieve l7 rules." msgstr "无法获取七层规则。" msgid "Unable to retrieve listener." msgstr "无法检索监听器。" msgid "Unable to retrieve listeners." msgstr "无法检索监听器。" msgid "Unable to retrieve load balancer." msgstr "无法检索负载均衡器。" msgid "Unable to retrieve load balancers." msgstr "无法检索负载均衡器。" msgid "Unable to retrieve member." msgstr "无法检索成员。" msgid "Unable to retrieve members." msgstr "无法检索成员。" msgid "Unable to retrieve pool." msgstr "无法检索资源池。" msgid "Unable to retrieve pools." msgstr "无法检索资源池。" msgid "Unable to retrieve secrets." msgstr "无法获取密匙。" msgid "Unable to update flavor profile." msgstr "无法更新实例类型配置集。" msgid "Unable to update flavor." msgstr "无法更新实例类型。" msgid "Unable to update health monitor." msgstr "无法更新健康监控。" msgid "Unable to update l7 policy." msgstr "无法更新七层策略。" msgid "Unable to update l7 rule." msgstr "无法更新七层规则。" msgid "Unable to update listener." msgstr "无法更新监听器。" msgid "Unable to update load balancer." msgstr "无法更新负载均衡器。" msgid "Unable to update member list." msgstr "无法更新成员列表。" msgid "Unable to update member." msgstr "无法更新成员。" msgid "Unable to update pool." msgstr "无法更新资源池。" msgid "Update" msgstr "更新" msgid "Update Health Monitor" msgstr "更新健康监控器。" msgid "Update L7 Policy" msgstr "更新七层策略" msgid "Update L7 Rule" msgstr "更新七层规则" msgid "Update Listener" msgstr "更新监听器" msgid "Update Load Balancer" msgstr "更新负载均衡器" msgid "Update Member" msgstr "更新成员" msgid "Update Pool" msgstr "更新资源池" msgid "Updated At" msgstr "更新于" msgid "" "Use the key-manager service to create any certificate containers before " "creating the listener.\n" " The following documentation provides information on how to create a " "certificate container:" msgstr "" "创建监听器前,使用 key-manager 服务创建所有证书容器。\n" "下面的文档介绍了如何创建一个证书容器:" msgid "Value" msgstr "值" msgid "Value:" msgstr "值:" msgid "Weight" msgstr "权重" msgid "Weight:" msgstr "权重:" msgid "" "When true the logic of the rule is inverted. For example, with invert\n" " true, equal to would become not equal to." msgstr "为是时该规则将被反转。例如,反转为是时相同将变成不相同。" msgid "X-Forwarded-For" msgstr "X-Forwarded-For" msgid "X-Forwarded-Port" msgstr "X-Forwarded-Port" msgid "X-Forwarded-Proto" msgstr "X-Forwarded-Proto" msgid "Yes" msgstr "是" #, python-format msgid "" "You are about to disassociate the floating IP address from load balancer \"%s" "\". Please confirm." msgstr "你将从负载均衡器解除浮动 IP 地址关联“%s”,请确认。" #, python-format msgid "You have selected \"%s\". Deleted L7 Policy is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted L7 Policies are not recoverable." msgstr[0] "你选择了“%s”。删除的七层策略无法恢复。" #, python-format msgid "You have selected \"%s\". Deleted L7 Rule is not recoverable." msgid_plural "You have selected \"%s\". Deleted L7 Rules are not recoverable." msgstr[0] "你选择了“%s”。删除的七层规则无法恢复。" #, python-format msgid "You have selected \"%s\". Deleted health monitor is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted health monitors are not recoverable." msgstr[0] "你选择了“%s”。删除的健康监控器无法恢复。" #, python-format msgid "You have selected \"%s\". Deleted listener is not recoverable." msgid_plural "You have selected \"%s\". Deleted listeners are not recoverable." msgstr[0] "你选择了“%s”。删除的监听器无法恢复。" #, python-format msgid "" "You have selected \"%s\". Deleted load balancer is not recoverable and this " "deletion will delete all of the sub-resources." msgid_plural "" "You have selected \"%s\". Deleted load balancers are not recoverable and " "this deletion will delete all of the sub-resources." msgstr[0] "" "您选择了 \"%s\"。删除的负载均衡器将无法被恢复,这个删除操作将删除所有子资源。" #, python-format msgid "You have selected \"%s\". Deleted member is not recoverable." msgid_plural "You have selected \"%s\". Deleted members are not recoverable." msgstr[0] "你选择了“%s”。删除的成员无法恢复。" #, python-format msgid "You have selected \"%s\". Deleted pool is not recoverable." msgid_plural "You have selected \"%s\". Deleted pools are not recoverable." msgstr[0] "你选择了“%s”。删除的资源池无法恢复。" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4541008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/zh_Hant/0000775000175100017510000000000015033037476023501 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/zh_Hant/LC_MESSAGES/0000775000175100017510000000000015033037476025266 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/zh_Hant/LC_MESSAGES/django.po0000664000175100017510000000115215033037474027065 0ustar00mylesmyles# Jacky Hu , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2021-02-28 17:23+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-06-03 01:22+0000\n" "Last-Translator: Copied by Zanata \n" "Language-Team: Chinese (China)\n" "Language: zh_TW\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "Load Balancers" msgstr "負載均衡器" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/locale/zh_Hant/LC_MESSAGES/djangojs.po0000664000175100017510000010605115033037474027426 0ustar00mylesmyles# Jacky Hu , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2022-08-16 20:34+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-08-18 02:54+0000\n" "Last-Translator: Jacky Hu \n" "Language-Team: Chinese (China)\n" "Language: zh_TW\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" #, python-format msgid "%(ip)s..." msgstr "%(ip)s..." msgid "A new health monitor is being created." msgstr "一個新的健康監控器正在創建。" msgid "A new l7 policy is being created." msgstr "一個新的七層策略正在被創建" msgid "A new listener is being created." msgstr "一個新的監聽器正在創建。" msgid "A new load balancer is being created." msgstr "一個新的負載均衡器正在創建。" msgid "A new pool is being created." msgstr "一個新的資源池正在創建。" msgid "" "A pool represents a group of members over which the load balancing will be " "applied." msgstr "資源池代表提供負載均衡器的一組成員。" msgid "APP_COOKIE: Session persistence based on application cookie." msgstr "APP_COOKIE:基于應用 COOKIE 的會話持久化。" msgid "Action" msgstr "行為" msgid "Action:" msgstr "行為:" msgid "Active" msgstr "運行中" msgid "Add" msgstr "添加" msgid "Add external member" msgstr "添加外部成員" msgid "Add members to the load balancer pool." msgstr "為負載均衡池添加成員。" msgid "Add/Remove Members" msgstr "添加/移除成員" msgid "Add/Remove Pool Members" msgstr "添加/移除資源池成員" msgid "Admin State Up" msgstr "管理狀態:啟動" msgid "Algorithm" msgstr "算法" msgid "Algorithm:" msgstr "算法:" msgid "Allocated Members" msgstr "分配成員" msgid "" "An L7 Policy is a collection of L7 rules associated with a Listener, and " "which may also have an association to a back-end pool" msgstr "一個七層策略是關聯于監聽器的七層規則的集,監聽器可能有一個關聯的資源池" msgid "" "An L7 Rule is a single, simple logical test which returns either true or\n" "false." msgstr "一個七層規則是返回是或否的單一簡單邏輯測試" msgid "" "An alternate IP address used for health monitoring a backend member.\n" " Default is null which monitors the member address." msgstr "" "用於後端成員健康監控的 IP 地址。\n" "預設是空時監測該成員地址。" msgid "" "An alternate protocol port used for health monitoring a backend member.\n" " Default is null which monitors the member protocol port." msgstr "" "用於後端成員健康監控的協議連接埠。\n" "預設是空時監測該成員協議連接埠。" msgid "An error occurred. Please try again later." msgstr "發生錯誤,請稍後重試。" msgid "Associate" msgstr "關聯" msgid "Associate Floating IP" msgstr "關聯浮動 IP" msgid "Associate Floating IP Address" msgstr "關聯浮動 IP 地址" msgid "Associating floating IP with load balancer." msgstr "為負載均衡器關聯浮動 IP。" msgid "Available Instances" msgstr "可用實例" msgid "Backend member connection timeout in milliseconds. Default: 5000." msgstr "後端成員連接超時時限,單位是毫秒,預設值:5000。" msgid "Backend member inactivity timeout in milliseconds. Default: 50000." msgstr "後端成員閒置超時時限,單位是毫秒,預設值:50000。" msgid "Backup" msgstr "備份" msgid "Backup:" msgstr "備份:" msgid "CONTAINS: String contains." msgstr "包含:字元串包含。" msgid "" "COOKIE: The rule looks for a cookie named by the key parameter and\n" " compares it against the value parameter in the rule." msgstr "COOKIE:該規則查找以鍵參數命名的 COOKIE 並將其與值參數相比較。" msgid "Cancel" msgstr "取消" msgid "Certificate Name" msgstr "證書名稱" msgid "Client Data Timeout" msgstr "客戶數據超時時限" msgid "Client Data Timeout:" msgstr "客戶數據超時時限:" msgid "Compare Type" msgstr "比較類型" msgid "Compare Type:" msgstr "比較類型:" msgid "Confirm Delete Health Monitor" msgid_plural "Confirm Delete Health Monitors" msgstr[0] "確認刪除健康監控器" msgid "Confirm Delete L7 Policy" msgid_plural "Confirm Delete L7 Policies" msgstr[0] "確認刪除七層策略" msgid "Confirm Delete L7 Rule" msgid_plural "Confirm Delete L7 Rules" msgstr[0] "確認刪除七層規則" msgid "Confirm Delete Listener" msgid_plural "Confirm Delete Listeners" msgstr[0] "確認刪除監聽器" msgid "Confirm Delete Load Balancer" msgid_plural "Confirm Delete Load Balancers" msgstr[0] "確認刪除負載均衡器" msgid "Confirm Delete Member" msgid_plural "Confirm Delete Members" msgstr[0] "確認刪除成員" msgid "Confirm Delete Pool" msgid_plural "Confirm Delete Pools" msgstr[0] "確認刪除資源池" msgid "Confirm Disassociate Floating IP Address" msgstr "確認解除關聯浮動 IP 地址。" msgid "Connection Limit" msgstr "連接限制" msgid "Connection Limit:" msgstr "連接限制:" msgid "Contains" msgstr "包含" msgid "Cookie" msgstr "Cookie" msgid "Cookie Name" msgstr "Cookie 名稱" msgid "Create Health Monitor" msgstr "創建健康監控器。" msgid "Create L7 Policy" msgstr "創建七層策略" msgid "Create L7 Rule" msgstr "創建七層規則" msgid "Create Listener" msgstr "創建監控器" msgid "Create Load Balancer" msgstr "創建負載均衡器" msgid "Create Pool" msgstr "創建資源池" msgid "Created At" msgstr "創建於" msgid "Default Pool ID" msgstr "預設資源池 ID" msgid "Default Pool ID:" msgstr "預設資源池 ID:" msgid "Default TLS Container Ref" msgstr "預設 TLS 容器編號" msgid "Degraded" msgstr "衰退" msgid "Delay" msgstr "延遲" msgid "Delay (sec)" msgstr "延遲(秒)" msgid "Delay:" msgstr "延遲:" msgid "Delete Health Monitor" msgid_plural "Delete Health Monitors" msgstr[0] "刪除健康監控" msgid "Delete Health Monitors" msgstr "刪除健康監控" msgid "Delete L7 Policies" msgstr "刪除七層策略" msgid "Delete L7 Policy" msgid_plural "Delete L7 Policies" msgstr[0] "刪除七層策略" msgid "Delete L7 Rule" msgid_plural "Delete L7 Rules" msgstr[0] "刪除七層規則" msgid "Delete L7 Rules" msgstr "刪除七層規則" msgid "Delete Listener" msgid_plural "Delete Listeners" msgstr[0] "刪除監控器" msgid "Delete Listeners" msgstr "刪除監控器" msgid "Delete Load Balancer" msgid_plural "Delete Load Balancers" msgstr[0] "刪除負載均衡器" msgid "Delete Load Balancers" msgstr "刪除負載均衡器" msgid "Delete Member" msgid_plural "Delete Members" msgstr[0] "刪除成員" msgid "Delete Members" msgstr "刪除成員" msgid "Delete Pool" msgid_plural "Delete Pools" msgstr[0] "刪除資源池" msgid "Delete Pools" msgstr "刪除資源池" #, python-format msgid "Deleted Health Monitor: %s." msgid_plural "Deleted Health Monitors: %s." msgstr[0] "刪除的健康監控器:%s。" #, python-format msgid "Deleted L7 Policy: %s." msgid_plural "Deleted L7 Policies: %s." msgstr[0] "刪除的七層策略:%s。" #, python-format msgid "Deleted L7 Rule: %s." msgid_plural "Deleted L7 Rules: %s." msgstr[0] "刪除的七層規則:%s。" #, python-format msgid "Deleted Listener: %s." msgid_plural "Deleted Listeners: %s." msgstr[0] "刪除的監聽器:%s。" #, python-format msgid "Deleted Load Balancer: %s." msgid_plural "Deleted Load Balancers: %s." msgstr[0] "刪除的負載均衡器:%s。" #, python-format msgid "Deleted Member: %s." msgid_plural "Deleted Members: %s." msgstr[0] "刪除的成員:%s。" #, python-format msgid "Deleted Pool: %s." msgid_plural "Deleted Pools: %s." msgstr[0] "刪除的資源池:%s。" msgid "Description" msgstr "描述" msgid "Disassociate" msgstr "取消關聯" msgid "Disassociate Floating IP" msgstr "解除關聯浮動 IP" #, python-format msgid "Disassociated floating IP address from load balancer: %s." msgstr "已從負載均衡器取解除浮動IP關聯:%s。" msgid "ENDS_WITH: String ends with." msgstr "ENDS_WITH:字元串尾碼。" msgid "EQUAL_TO: String is equal to." msgstr "EQUAL_TO:字元串相同。" msgid "" "Each port that listens for traffic on a particular load balancer is " "configured separately and\n" " tied to the load balancer. Multiple listeners can be associated with the " "same load balancer but\n" " each must use a unique port." msgstr "" "負載均衡器中的每一個監聽的連接埠獨立地配置並與負載均衡器關聯。\n" "多個監聽器可以關聯到同一個負載均衡器上,\n" "但每個都必須使用唯一的連接埠。" msgid "Edit Health Monitor" msgstr "編輯健康監控" msgid "Edit L7 Policy" msgstr "編輯七層策略" msgid "Edit L7 Rule" msgstr "編輯七層規則" msgid "Edit Listener" msgstr "編輯監控器" msgid "Edit Load Balancer" msgstr "編輯負載均衡器" msgid "Edit Member" msgstr "編輯成員" msgid "Edit Pool" msgstr "編輯資源池" msgid "Ends With" msgstr "結束于" msgid "Equal To" msgstr "等於" msgid "Error" msgstr "錯誤" msgid "Expected Codes" msgstr "預期的狀態碼" msgid "Expected Codes:" msgstr "預期的狀態碼:" msgid "Expiration Date" msgstr "截止日期" msgid "" "FILE_TYPE: The rule compares the last portion of the URI against\n" " the value parameter in the rule. (eg. \"txt\", \"jpg\", etc.)" msgstr "FILE_TYPE:該規則將 URI 的尾碼與值參數相比較。(例如:“txt”,“jpg”。)" msgid "File Type" msgstr "檔案類型" msgid "Flavor" msgstr "類型" msgid "Floating IP" msgstr "浮動 IP" msgid "Floating IP address or pool" msgstr "浮動 IP 地址或浮動 IP 地址池" msgid "Floating IP addresses" msgstr "浮動 IP 地址" msgid "Floating IP pools" msgstr "浮動 IP 資源池" msgid "Frontend client inactivity timeout in milliseconds. Default: 50000." msgstr "前端客戶閒置超時時限,單位是毫秒,預設值:50000。" msgid "" "HEADER: The rule looks for a header defined in the key parameter\n" " and compares it against the value parameter in the rule." msgstr "HEADER:該規則查找以鍵參數命名的報頭並將其與值參數相比較。" msgid "" "HOST_NAME: The rule does a comparison between the HTTP/1.1\n" " hostname in the request against the value parameter in the rule." msgstr "HOST_NAME:該規則將請求中的 HTTP/1.1 主機名與值參數相比較。" msgid "HTTP Method" msgstr "HTTP 方法" msgid "HTTP Method:" msgstr "HTTP 方法:" msgid "HTTP_COOKIE: Session persistence based on http cookie." msgstr "HTTP_COOKIE:基于 HTTP COOKIE 的會話持久化。" msgid "Header" msgstr "報頭" msgid "Health Monitor" msgstr "健康監控" msgid "Health Monitor ID" msgstr "健康監控器 ID" msgid "Health Monitors" msgstr "健康監控" msgid "Host Name" msgstr "主機名" msgid "ID" msgstr "ID" msgid "IP Address" msgstr "IP 地址" #, python-format msgid "IP Addresses (%(count)s)" msgstr "IP 地址(%(count)s)" msgid "IP address" msgstr "IP 地址" msgid "IP address:" msgstr "IP 地址:" msgid "" "If an IP address is provided it must be a well-formed IPv4 or IPv6 address. " "The system will\n" " attempt to assign the provided IP address to the load balancer. If an IP " "address is not provided\n" " then one will be allocated for you." msgstr "" "IP地址必須為格式良好的 IPv4 或 IPv6 地址。\n" "系統嘗試為負載均衡器分配提供的 IP 地址。\n" "如果沒有提供 IP 地址,則需要你手動分配一個 IP。" msgid "" "If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL " "certificates must\n" " be selected. The first certificate will be the default." msgstr "" "如果監聽器使用 TERMINATED_HTTPS 協議,則必須選擇一個或多個 SSL 證書。\n" "預設選擇第一個。" msgid "Inactive" msgstr "閒置" msgid "Insert Headers" msgstr "插入報頭" msgid "Insert Headers:" msgstr "插入報頭:" msgid "Invert" msgstr "反轉" msgid "Invert:" msgstr "反轉:" msgid "" "Is the member a backup? Backup members only receive traffic when all\n" " non-backup members are down." msgstr "該成員是否為備份?備份成員僅當所有非備份成員不可用時才接收通信。" msgid "Key" msgstr "鍵" msgid "Key Manager API Guide: Creating a Certificate Container" msgstr "Key Manager API 指南:創建證書容器" msgid "Key Manager Service Command-Line Client" msgstr "Key Manager 服務命令行客戶端" msgid "Key:" msgstr "鍵:" msgid "L7 Policies" msgstr "七層策略" msgid "L7 Policy" msgstr "七層策略" msgid "L7 Policy Details" msgstr "七層策略詳情" msgid "L7 Rule" msgstr "七層規則" msgid "L7 Rule Details" msgstr "七層規則詳情" msgid "L7 Rules" msgstr "七層規則" msgid "" "LEAST_CONNECTIONS: Allocates requests to the instance with the least number " "of active\n" " connections." msgstr "LEAST_CONNECTIONS:分發至最少活動連接次數的實例。" msgid "Least Connections" msgstr "最少連接數" msgid "Listener" msgstr "監控器" msgid "Listener Details" msgstr "監聽器詳情" msgid "Listener ID" msgstr "監聽器ID" msgid "Listeners" msgstr "監控器" msgid "Load Balancer" msgstr "負載均衡器" msgid "Load Balancer Details" msgstr "負載均衡器詳情" msgid "Load Balancers" msgstr "負載均衡器" msgid "Loading" msgstr "加載中" msgid "Max Retries" msgstr "最大嘗試次數" msgid "Max Retries Down" msgstr "最大失敗嘗試次數" msgid "Max Retries Down:" msgstr "最大失敗重試次數:" msgid "Max Retries:" msgstr "最大重試次數:" msgid "Member" msgstr "成員" msgid "Member Connect Timeout" msgstr "成員連接超時時限" msgid "Member Connect Timeout:" msgstr "成員連接超時時限:" msgid "Member Data Timeout" msgstr "成員數據超時時限" msgid "Member Data Timeout:" msgstr "成員數據超時時限:" msgid "Members" msgstr "成員" msgid "" "Members are the actual IP addresses that will receive traffic from the load " "balancer. Each\n" " member must have a unique combination of IP address and port." msgstr "" "成員是在負載均衡器中通信的實際 IP 地址。\n" "每個成員必須有一個唯一關聯的 IP 地址和連接埠。" msgid "Monitor Address" msgstr "健康監聽器地址" msgid "Monitor Address:" msgstr "健康監控器地址:" msgid "Monitor Details" msgstr "健康監控器詳情" msgid "Monitor Port" msgstr "健康監聽器連接埠" msgid "Monitor Port:" msgstr "健康監控器連接埠:" msgid "Name" msgstr "名稱" msgid "Network" msgstr "網絡" msgid "Network ID" msgstr "網絡 ID" msgid "No" msgstr "否" msgid "No Monitor" msgstr "無健康監控" msgid "No available certificates" msgstr "無可用證書" msgid "No available instances" msgstr "無可用實例" msgid "No items to display." msgstr "沒有要顯示的項目。" msgid "No members have been allocated" msgstr "沒有成員已分配" msgid "None" msgstr "無" msgid "Offline" msgstr "離線" msgid "Online" msgstr "在綫" msgid "Operating Status" msgstr "操作狀態" msgid "Overview" msgstr "概覽" msgid "" "PATH: The rule compares the path portion of the HTTP URI against\n" " the value parameter in the rule." msgstr "PATH:該規則將 HTTP URI 的路徑部分與值參數相比較。" msgid "Path" msgstr "路徑" msgid "Pending Create" msgstr "暫掛創建" msgid "Pending Delete" msgstr "暫掛刪除" msgid "Pending Update" msgstr "暫掛更新" msgid "Please Wait" msgstr "請等待" msgid "Pool" msgstr "資源池" msgid "Pool Details" msgstr "資源池詳情" msgid "Pool Members" msgstr "資源池成員" msgid "Pool member has been updated." msgstr "資源池成員已更新" msgid "Pools" msgstr "資源池" msgid "Port" msgstr "連接埠" msgid "Port ID" msgstr "連接埠 ID" msgid "Port:" msgstr "連接埠:" msgid "Position" msgstr "位置" msgid "Position:" msgstr "位置:" msgid "Project" msgstr "項目" msgid "Project ID" msgstr "項目 ID" msgid "Protocol" msgstr "協議" msgid "Protocol Port" msgstr "協議連接埠" msgid "Protocol:" msgstr "協議:" msgid "Provide the details for the health monitor." msgstr "為健康監控提供詳情。" msgid "Provide the details for the l7 policy." msgstr "提供七層策略的詳情。" msgid "Provide the details for the l7 rule." msgstr "提供七層規則的詳情。" msgid "Provide the details for the listener." msgstr "為監聽器提供詳情。" msgid "Provide the details for the load balancer." msgstr "為負載均衡器提供詳情。" msgid "Provide the details for the member." msgstr "為成員提供詳情。" msgid "Provide the details for the pool." msgstr "為資源池提供詳情。" msgid "Provider" msgstr "提供者" msgid "Provisioning Status" msgstr "配置狀態" msgid "" "REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated " "with the L7 policy." msgstr "REDIRECT_TO_POOL:請求被轉發到該七層策略關聯的資源池。" msgid "" "REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in " "the redirect_url parameter." msgstr "" "REDIRECT_TO_URL:請求被作為一個 HTTP 重定向發送到 redirect_url 參數里定義的 " "URL。" msgid "REGEX: Perl type regular expression matching." msgstr "REGEX:Perl 正則表達式匹配。" msgid "" "REJECT: The request is denied with an appropriate response code, and not " "forwarded on to any back-end pool." msgstr "REJECT:請求被拒絶並返回合適的狀態碼,並不被轉發給任何資源池" msgid "ROUND_ROBIN: Rotates requests evenly between multiple instances." msgstr "ROUND_ROBIN:在多個實例之間輪詢分發。" msgid "Redirect Pool ID" msgstr "重定向資源池 ID" msgid "Redirect Pool ID:" msgstr "重定向資源池 ID:" msgid "Redirect URL" msgstr "重定向 URL" msgid "Redirect URL:" msgstr "重定向 URL:" msgid "Redirect to Pool" msgstr "重定向到資源池" msgid "Redirect to URL" msgstr "重定向到 URL" msgid "Regex" msgstr "正則表達式" msgid "Reject" msgstr "拒絶" msgid "Remove" msgstr "移除" msgid "" "Requests matching this policy will be redirected to the pool with this ID. " "Only valid if action is REDIRECT_TO_POOL." msgstr "" "與該策略相匹配的請求將被重定向到由 ID 指定的資源池。僅當行為是 " "REDIRECT_TO_POOL 時有效。" msgid "" "Requests matching this policy will be redirected to this URL. Only valid if " "action is REDIRECT_TO_URL." msgstr "" "與該策略相匹配的請求將被重定向指定的 URL。僅當行為是 REDIRECT_TO_URL 時有效。" msgid "Round Robin" msgstr "輪詢" msgid "Rules" msgstr "規則" msgid "SNI Container Refs" msgstr "SNI 容器編號" msgid "" "SOURCE_IP: Requests from a unique source IP address are consistently " "directed to the same instance." msgstr "SOURCE_IP:來自相同源IP地址的請求連續的發送到同一實例。" msgid "SOURCE_IP: Session persistence based on source ip." msgstr "SOURCE_IP:基于源 IP 地址的會話持久化。" msgid "SSL Certificates" msgstr "SSL 證書" msgid "STARTS_WITH: String starts with." msgstr "STARTS_WITH:字元串首碼。" msgid "" "Select a floating IP address to associate with the load balancer or a " "floating IP pool in which to allocate a new floating IP address." msgstr "" "選擇一個浮動 IP 地址關聯一個負載均衡器或為浮動 IP 池分配一個新的浮動 IP 地址" "池。" msgid "Select certificates from the available certificates below" msgstr "從下面可選的證書中選擇證書" msgid "Select one or more SSL certificates for the listener." msgstr "為監聽器選擇一個或多個 SSL 證書。" msgid "Session Persistence" msgstr "會話持久化" msgid "Session Persistence:" msgstr "會話持久化:" msgid "Source IP" msgstr "源IP" msgid "Starts With" msgstr "開始於" msgid "Subnet" msgstr "子網" msgid "Subnet ID" msgstr "子網 ID" msgid "Subnet:" msgstr "子網:" msgid "TCP Inspect Timeout" msgstr "TCP 監測超時時限" msgid "TCP Inspect Timeout:" msgstr "TCP 監測超時時限:" msgid "" "The Available Instances table contains existing compute instances that can " "be added as members\n" " of the pool. Use the \"Add external member\" button to add a member not " "found in the Available\n" " Instances table." msgstr "" "可用實例表顯示了存在的可以添加為資源池成員的計算實例。\n" "使用“添加外部成員”按鈕可以添加在可用實例表中找不到的成員。" msgid "The HTTP method used to perform the health check." msgstr "用來進行健康檢查的 HTTP 請求方式。" msgid "The ID of the pool used by the listener if no L7 policies match." msgstr "無七層策略匹配時用於該監聽器的資源池 ID。" msgid "The IP address is not valid." msgstr "IP 地址無效。" msgid "" "The IP address of the member to receive traffic from the load balancer. Must " "be a well-formed\n" " IPv4 or IPv6 address." msgstr "" "用於從負載均衡器中接收消息成員的 IP 地址。\n" "必須使用格式良好的 IPv4 或 IPv6 地址。" msgid "" "The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL." msgstr "七層策略行為。REJECT,REDIRECT_TO_URL,REDIRECT_TO_POOL 其中之一" msgid "The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH." msgstr "七層規則類型。COOKIE,FILE_TYPE,HEADER,HOST_NAME,PATH 之中之一。" msgid "The URL path is not valid." msgstr "URL 路徑無效。" msgid "" "The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH,\n" " EQUAL_TO, REGEX, or STARTS_WITH." msgstr "" "七層規則的比較類型。CONTAINS,ENDS_WITH,EQUAL_TO,REGEX,STARTS_WITH 其中之" "一。" msgid "The connection limit must be a number greater than or equal to -1." msgstr "連接限制必須是大於或等於 -1 的整數。" msgid "" "The expected HTTP status codes to get from a successful health check. Must " "be a single number,\n" " a comma separated list of numbers, or a range (two numbers separated by a " "hyphen)." msgstr "" "健康檢查成功返回的期望 HTTP 狀態碼。\n" "必須為單個數字,逗號分隔的一組數字或一個範圍(用連接符分隔的兩個數字)。" msgid "The expected status code is not valid." msgstr "期望狀態碼無效。" msgid "The health monitor has been updated." msgstr "健康監控器已經更新。" msgid "" "The health monitor is used to determine the health of your pool members. " "Health checks\n" " routinely run against each member within the pool and the result of the " "health check is used\n" " to determine if the member receives new connections. Each pool can only " "have one health\n" " monitor." msgstr "" "健康監控用來確定你的資源池成員的健康狀況。\n" "健康檢查通常在資源池中與每個成員隔離運行,健康檢查的結果通過成員接收到新的連" "接來確定。\n" "每個資源池只能有一個健康監控。" msgid "" "The interval between health checks. Must be greater than or equal to the " "timeout." msgstr "健康檢查之間時間間隔,必須大於或等於超時時限。" msgid "" "The key to use for the comparison. For example, the name of the cookie\n" " to evaluate." msgstr "用於比較的鍵。例如 COOKIE 的名字。" msgid "The l7policy has been updated." msgstr "七層策略已更新" msgid "The l7rule has been updated." msgstr "七層規則已更新" msgid "The listener has been updated." msgstr "監聽器已更新。" msgid "" "The load balancer algorithm that distributes traffic to the pool members." msgstr "用於分發消息給資源池成員的負載均衡算法。" msgid "The load balancer has been updated." msgstr "負載均衡器已更新。" msgid "" "The load balancer occupies a neutron network port and has an IP address " "assigned from a subnet." msgstr "負載均衡器占用一個 neutron 網絡連接埠和一個子網分配的 IP 地址。" msgid "The max retry count must be a number between 1 and 10." msgstr "健康檢查間隔必須大於或等於超時時限。" msgid "The max retry down count must be a number between 1 and 10." msgstr "最大失敗嘗試次數必須是 1 至 10 之間的整數。" msgid "" "The maximum number of connections permitted for this listener.\n" " Default value is -1 which represents infinite connections." msgstr "該監聽器允許的最大連接數。預設值 -1 表示無限制。" msgid "The monitor address must be a valid IP address." msgstr "健康監聽器地址必須是有效的 IP 地址。" msgid "The monitor port must be a number between 1 and 65535." msgstr "健康監聽器連接埠必須是 1 至 65535 的整數" msgid "The network on which to allocate the load balancer's IP address." msgstr "給分配負載均衡器 IP 地址的網絡。" msgid "The network which contains the IP address of the member." msgstr "關聯成員 IP 地址的網絡。" msgid "" "The number of allowed connection failures before marking the member as " "error. Must be a\n" " number from 1 to 10. The default is 3." msgstr "" "在將成員標記為錯誤之前,允許連接失敗的次數。\n" "必須是 1 至 10 之間的整數。預設值是 3。" msgid "" "The number of allowed connection failures before marking the member as " "inactive. Must be a\n" " number from 1 to 10." msgstr "" "在將成員標記為未活動狀態之前,允許連接失敗的次數。\n" "必須是 1 至 10 之間的整數。" msgid "The pool has been updated." msgstr "資源池已更新。" msgid "The pool members have been updated." msgstr "資源池成員已更新" msgid "The port must be a number between 1 and 65535." msgstr "連接埠必須是 1 至 65536 之間的整數。" msgid "" "The port must be unique among all listeners attached to this load balancer." msgstr "負載均衡器上的所有監聽器的連接埠號必須唯一。" msgid "" "The port on which the front end listens. Must be an integer from 1 to 65535." msgstr "用來通信的成員監聽連接埠。必須是 1 至 65536 之間的整數。" msgid "" "The port on which the member listens for traffic. Must be a number from 1 to " "65535." msgstr "用來通信的成員監聽連接埠。必須是 1 至 65536 之間的整數。" msgid "The position must be a number between 1 and 2147483647." msgstr "位置必須是一個 1 至 2147483647 的整數。" msgid "The position of this policy on the listener. Positions start at 1." msgstr "該策略在監聽器裡的位置。位置從一開始。" msgid "" "The protocol for which the front end listens. The TERMINATED_HTTPS protocol " "is only available if\n" " the key-manager service is enabled and you have authority to list " "certificate containers and\n" " secrets." msgstr "" "監聽器之間通信的協議。\n" "TERMINATED_HTTPS 協議只有在 key-manager 服務可用\n" "並且你有權限查詢證書容器和密鑰的情況下才有用。" msgid "The redirect url must be a valid http or https url." msgstr "重定向 URL 必須是一個有效的 HTTP 或 HTTPS URL" msgid "" "The target of the health check HTTP request to the member. Must be a valid " "URL path." msgstr "成員發送健康檢查 HTTP 請求的目標地址,必須為合法的 URL 路徑。" msgid "" "The time after which a health check times out. Must be a number greater than " "or equal to 0\n" " and less than or equal to the interval." msgstr "" "健康檢查請求超時的時間。\n" "必須為大於或等於 0 的整數,並小於或等於間隔時間。" msgid "The timeout must be a number between 0 and 31536000000." msgstr "超時時限必須是 0 至 31536000000 的整數。" msgid "The timeout must be a number greater than or equal to 0." msgstr "超時時限必須是一個大於等於 0 的整數。" msgid "" "The type of session persistence for distributing traffic to the pool members." msgstr "用於為資源池成員分發消息的會話持久化類型。" msgid "" "The value to use for the comparison. For example, the file type to compare." msgstr "用於比較的值。例如要比較的檔案類型。" msgid "" "Time, in milliseconds, to wait for additional TCP packets for content\n" " inspection. Default: 0." msgstr "等待額外 TCP 內容監測包的超時時限,單位是毫秒,預設值:0。" msgid "Timeout" msgstr "超時時限" msgid "Timeout (sec)" msgstr "超時時限(秒)" msgid "Timeout:" msgstr "超時時限:" msgid "Type" msgstr "類型" msgid "Type:" msgstr "類型:" msgid "URL Path" msgstr "URL 路徑" msgid "URL Path:" msgstr "URL 路徑:" msgid "Unable to create health monitor." msgstr "無法創建健康監控。" msgid "Unable to create l7 policy." msgstr "無法創建七層策略。" msgid "Unable to create l7 rule." msgstr "無法創建七層規則。" msgid "Unable to create listener." msgstr "無法創建監聽器。" msgid "Unable to create load balancer." msgstr "無法創建負載均衡器。" msgid "Unable to create pool." msgstr "無法創建資源池。" #, python-format msgid "Unable to delete Health Monitor: %s." msgid_plural "Unable to delete Health Monitors: %s." msgstr[0] "無法刪除健康監控:%s。" #, python-format msgid "Unable to delete L7 Policy: %s." msgid_plural "Unable to delete L7 Policies: %s." msgstr[0] "無法刪除七層策略:%s。" #, python-format msgid "Unable to delete L7 Rule: %s." msgid_plural "Unable to delete L7 Rules: %s." msgstr[0] "無法刪除七層規則:%s。" #, python-format msgid "Unable to delete Listener: %s." msgid_plural "Unable to delete Listeners: %s." msgstr[0] "無法刪除監聽器:%s。" #, python-format msgid "Unable to delete Load Balancer: %s." msgid_plural "Unable to delete Load Balancers: %s." msgstr[0] "無法刪除負載均衡器:%s。" #, python-format msgid "Unable to delete Member: %s." msgid_plural "Unable to delete Members: %s." msgstr[0] "無法刪除成員:%s。" #, python-format msgid "Unable to delete Pool: %s." msgid_plural "Unable to delete Pools: %s." msgstr[0] "無法刪除資源池:%s。" msgid "Unable to delete health monitor." msgstr "無法刪除健康監控。" msgid "Unable to delete l7 policy." msgstr "無法刪除七層策略。" msgid "Unable to delete l7 rule." msgstr "無法刪除七層規則。" msgid "Unable to delete listener." msgstr "無法刪除監聽器。" msgid "Unable to delete load balancer." msgstr "無法刪除負載均衡器。" msgid "Unable to delete member." msgstr "無法刪除成員。" msgid "Unable to delete pool." msgstr "無法刪除資源池。" #, python-format msgid "Unable to disassociate floating IP address from load balancer: %s." msgstr "無法從負載均衡器解除浮動IP地址關聯:%s。" msgid "Unable to retrieve SSL certificates." msgstr "不能獲取 SSL 證書。" msgid "Unable to retrieve health monitor." msgstr "無法獲取健康監控。" msgid "Unable to retrieve health monitors." msgstr "無法獲取健康監控。" msgid "Unable to retrieve l7 policies." msgstr "無法獲取七層策略。" msgid "Unable to retrieve l7 policy." msgstr "無法獲取七層策略。" msgid "Unable to retrieve l7 rule." msgstr "無法獲取七層規則。" msgid "Unable to retrieve l7 rules." msgstr "無法獲取七層規則。" msgid "Unable to retrieve listener." msgstr "無法檢索監聽器。" msgid "Unable to retrieve listeners." msgstr "無法檢索監聽器。" msgid "Unable to retrieve load balancer." msgstr "無法檢索負載均衡器。" msgid "Unable to retrieve load balancers." msgstr "無法檢索負載均衡器。" msgid "Unable to retrieve member." msgstr "無法檢索成員。" msgid "Unable to retrieve members." msgstr "無法檢索成員。" msgid "Unable to retrieve pool." msgstr "無法檢索資源池。" msgid "Unable to retrieve pools." msgstr "無法檢索資源池。" msgid "Unable to retrieve secrets." msgstr "無法獲取密匙。" msgid "Unable to update health monitor." msgstr "無法更新健康監控。" msgid "Unable to update l7 policy." msgstr "無法更新七層策略。" msgid "Unable to update l7 rule." msgstr "無法更新七層規則。" msgid "Unable to update listener." msgstr "無法更新監聽器。" msgid "Unable to update load balancer." msgstr "無法更新負載均衡器。" msgid "Unable to update member list." msgstr "無法更新成員列表。" msgid "Unable to update member." msgstr "無法更新成員。" msgid "Unable to update pool." msgstr "無法更新資源池。" msgid "Update" msgstr "更新" msgid "Update Health Monitor" msgstr "更新健康監控器。" msgid "Update L7 Policy" msgstr "更新七層策略" msgid "Update L7 Rule" msgstr "更新七層規則" msgid "Update Listener" msgstr "更新監聽器" msgid "Update Load Balancer" msgstr "更新負載均衡器" msgid "Update Member" msgstr "更新成員" msgid "Update Pool" msgstr "更新資源池" msgid "Updated At" msgstr "更新于" msgid "" "Use the key-manager service to create any certificate containers before " "creating the listener.\n" " The following documentation provides information on how to create a " "certificate container:" msgstr "" "創建監聽器前,使用 key-manager 服務創建所有證書容器。\n" "下面的文檔介紹了如何創建一個證書容器:" msgid "Value" msgstr "值" msgid "Value:" msgstr "值:" msgid "Weight" msgstr "權重" msgid "Weight:" msgstr "權重:" msgid "" "When true the logic of the rule is inverted. For example, with invert\n" " true, equal to would become not equal to." msgstr "為是時該規則將被反轉。例如,反轉為是時相同將變成不相同。" msgid "X-Forwarded-For" msgstr "X-Forwarded-For" msgid "Yes" msgstr "是" #, python-format msgid "" "You are about to disassociate the floating IP address from load balancer \"%s" "\". Please confirm." msgstr "你將從負載均衡器解除浮動 IP 地址關聯“%s”,請確認。" #, python-format msgid "You have selected \"%s\". Deleted L7 Policy is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted L7 Policies are not recoverable." msgstr[0] "你選擇了“%s”。刪除的七層策略無法恢復。" #, python-format msgid "You have selected \"%s\". Deleted L7 Rule is not recoverable." msgid_plural "You have selected \"%s\". Deleted L7 Rules are not recoverable." msgstr[0] "你選擇了“%s”。刪除的七層規則無法恢復。" #, python-format msgid "You have selected \"%s\". Deleted health monitor is not recoverable." msgid_plural "" "You have selected \"%s\". Deleted health monitors are not recoverable." msgstr[0] "你選擇了“%s”。刪除的健康監控器無法恢復。" #, python-format msgid "You have selected \"%s\". Deleted listener is not recoverable." msgid_plural "You have selected \"%s\". Deleted listeners are not recoverable." msgstr[0] "你選擇了“%s”。刪除的監聽器無法恢復。" #, python-format msgid "You have selected \"%s\". Deleted member is not recoverable." msgid_plural "You have selected \"%s\". Deleted members are not recoverable." msgstr[0] "你選擇了“%s”。刪除的成員無法恢復。" #, python-format msgid "You have selected \"%s\". Deleted pool is not recoverable." msgid_plural "You have selected \"%s\". Deleted pools are not recoverable." msgstr[0] "你選擇了“%s”。刪除的資源池無法恢復。" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/post_install.sh0000775000175100017510000000067415033037474023726 0ustar00mylesmyles#!/bin/bash -x # This script will be executed inside npm postinstall task, see package.json # pull down the test shim from horizon master because it's not # included in the installed horizon packages if [ ! -f test-shim.js ]; then wget -nv -t 3 https://raw.githubusercontent.com/openstack/horizon/master/test-shim.js fi echo "Creating a tox env which will contain xStatic libraries, horizon, and openstack_dashboard" tox -ekarma --notest; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/sdk_connection.py0000664000175100017510000000426515033037474024226 0ustar00mylesmyles# Copyright Red Hat # # 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 django.conf import settings import octavia_dashboard from openstack import config as occ from openstack import connection from openstack_dashboard.api import base def get_sdk_connection(request): """Creates an SDK connection based on the request. :param request: Django request object :returns: SDK connection object """ # NOTE(mordred) Nothing says love like two inverted booleans # The config setting is NO_VERIFY which is, in fact, insecure. # get_one_cloud wants verify, so we pass 'not insecure' to verify. insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) # Pass interface to honor 'OPENSTACK_ENDPOINT_TYPE' interface = getattr(settings, 'OPENSTACK_ENDPOINT_TYPE', 'publicURL') # Pass load_yaml_config as this is a Django service with its own config # and we don't want to accidentally pick up a clouds.yaml file. We want to # use the settings we're passing in. cloud_config = occ.OpenStackConfig(load_yaml_config=False).get_one_cloud( verify=not insecure, cacert=cacert, interface=interface, region_name=request.user.services_region, auth_type='token', auth=dict( project_id=request.user.project_id, project_domain_id=request.user.domain_id, auth_token=request.user.token.unscoped_token, auth_url=base.url_for(request, 'identity')), app_name='octavia-dashboard', app_version=octavia_dashboard.__version__) return connection.from_config(cloud_config=cloud_config) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4541008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/0000775000175100017510000000000015033037476022136 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4541008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/0000775000175100017510000000000015033037476022716 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4541008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/0000775000175100017510000000000015033037476023646 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4661007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/openstack-service-api/0000775000175100017510000000000015033037476030042 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.servic0000664000175100017510000007221015033037474032611 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.app.core.openstack-service-api') .factory('horizon.app.core.openstack-service-api.lbaasv2', lbaasv2API); lbaasv2API.$inject = [ 'horizon.framework.util.http.service', 'horizon.framework.widgets.toast.service' ]; /** * @ngdoc service * @name horizon.app.core.openstack-service-api.loadbalancers * @description Provides direct pass through to Octavia with NO abstraction. * @param apiService The horizon core API service. * @param toastService The horizon toast service. * @returns The LBaaS V2 service API. */ function lbaasv2API(apiService, toastService) { var service = { getLoadBalancers: getLoadBalancers, getLoadBalancer: getLoadBalancer, deleteLoadBalancer: deleteLoadBalancer, createLoadBalancer: createLoadBalancer, editLoadBalancer: editLoadBalancer, getListeners: getListeners, getListener: getListener, createListener: createListener, editListener: editListener, deleteListener: deleteListener, getL7Policies: getL7Policies, getL7Policy: getL7Policy, createL7Policy: createL7Policy, editL7Policy: editL7Policy, deleteL7Policy: deleteL7Policy, getL7Rules: getL7Rules, getL7Rule: getL7Rule, createL7Rule: createL7Rule, editL7Rule: editL7Rule, deleteL7Rule: deleteL7Rule, getPools: getPools, getPool: getPool, createPool: createPool, editPool: editPool, deletePool: deletePool, getMembers: getMembers, getMember: getMember, deleteMember: deleteMember, editMember: editMember, getHealthMonitors: getHealthMonitors, getHealthMonitor: getHealthMonitor, deleteHealthMonitor: deleteHealthMonitor, createHealthMonitor: createHealthMonitor, editHealthMonitor: editHealthMonitor, updateMemberList: updateMemberList, getAvailabilityZones: getAvailabilityZones, getFlavors: getFlavors, getFlavor: getFlavor, deleteFlavor: deleteFlavor, createFlavor: createFlavor, editFlavor: editFlavor, getFlavorProfiles: getFlavorProfiles, getFlavorProfile: getFlavorProfile, deleteFlavorProfile: deleteFlavorProfile, createFlavorProfile: createFlavorProfile, editFlavorProfile: editFlavorProfile }; return service; /////////////// // Load Balancers /** * @name horizon.app.core.openstack-service-api.lbaasv2.getLoadBalancers * @description * Get a list of load balancers. * @param {boolean} full * The listing result is an object with property "items". Each item is * a load balancer. */ function getLoadBalancers(full) { var params = { full: full }; return apiService.get('/api/lbaas/loadbalancers/', { params: params }) .catch(function () { toastService.add('error', gettext('Unable to retrieve load balancers.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.getLoadBalancer * @description * Get a single load balancer by ID * @param {string} id * @param {boolean} full * Specifies the id of the load balancer to request. */ function getLoadBalancer(id, full) { var params = { full: full }; return apiService.get('/api/lbaas/loadbalancers/' + id + '/', { params: params }) .catch(function () { toastService.add('error', gettext('Unable to retrieve load balancer.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.deleteLoadBalancer * @description * Delete a single load balancer by ID * @param {string} id * Specifies the id of the load balancer to delete. * @param {boolean} quiet */ function deleteLoadBalancer(id, quiet) { var promise = apiService.delete('/api/lbaas/loadbalancers/' + id + '/'); return quiet ? promise : promise.catch(function () { toastService.add('error', gettext('Unable to delete load balancer.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.createLoadBalancer * @description * Create a new load balancer * @param {object} spec * Specifies the data used to create the new load balancer. */ function createLoadBalancer(spec) { return apiService.post('/api/lbaas/loadbalancers/', spec) .catch(function () { toastService.add('error', gettext('Unable to create load balancer.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.editLoadBalancer * @description * Edit a load balancer * @param {string} id * @param {object} spec * Specifies the data used to update the load balancer. */ function editLoadBalancer(id, spec) { return apiService.put('/api/lbaas/loadbalancers/' + id + '/', spec) .catch(function () { toastService.add('error', gettext('Unable to update load balancer.')); }); } // Listeners /** * @name horizon.app.core.openstack-service-api.lbaasv2.getListeners * @description * Get the list of listeners. * If a loadbalancer ID is passed as a parameter, the returning list of * listeners will be filtered to include only those listeners under the * specified loadbalancer. * @param {string} id * Specifies the id of the loadbalancer to request listeners for. * * The listing result is an object with property "items". Each item is * a listener. */ function getListeners(id) { var params = id ? {params: {loadbalancerId: id}} : {}; return apiService.get('/api/lbaas/listeners/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve listeners.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.getListener * @description * Get a single listener by ID. * @param {string} id * Specifies the id of the listener to request. * @param {boolean} includeChildResources * If truthy, all child resources below the listener will be included in the response. */ function getListener(id, includeChildResources) { var params = includeChildResources ? {params: {includeChildResources: includeChildResources}} : {}; return apiService.get('/api/lbaas/listeners/' + id + '/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve listener.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.createListener * @description * Create a new listener * @param {object} spec * Specifies the data used to create the new listener. */ function createListener(spec) { return apiService.post('/api/lbaas/listeners/', spec) .catch(function () { toastService.add('error', gettext('Unable to create listener.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.editListener * @description * Edit a listener * @param {string} id * Specifies the id of the listener to update. * @param {object} spec * Specifies the data used to update the listener. */ function editListener(id, spec) { return apiService.put('/api/lbaas/listeners/' + id + '/', spec) .catch(function () { toastService.add('error', gettext('Unable to update listener.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.deleteListener * @description * Delete a single listener by ID * @param {string} id * Specifies the id of the listener to delete. * @param {boolean} quiet */ function deleteListener(id, quiet) { var promise = apiService.delete('/api/lbaas/listeners/' + id + '/'); return quiet ? promise : promise.catch(function () { toastService.add('error', gettext('Unable to delete listener.')); }); } // Pools /** * @name horizon.app.core.openstack-service-api.lbaasv2.getPools * @description * Get the list of pools. * If a loadbalancer ID is passed as a parameter, the returning list of * pools will be filtered to include only those pools under the * specified loadbalancer. * @param {string} loadbalancerId * Specifies the id of the loadbalancer to request pools for. * @param {string} listenerId * Specifies the id of the listener to request pools for. * * The listing result is an object with property "items". Each item is * a pool. */ function getPools(loadbalancerId, listenerId) { var params = $.extend({}, { loadbalancerId: loadbalancerId, listenerId: listenerId } ); if (!$.isEmptyObject(params)) { params = { params: params }; } return apiService.get('/api/lbaas/pools/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve pools.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.getPool * @description * Get a single Pool by ID. * @param {string} id * Specifies the id of the pool to request. * @param {boolean} includeChildResources * If truthy, all child resources below the pool will be included in the response. */ function getPool(id, includeChildResources) { var params = includeChildResources ? {params: {includeChildResources: includeChildResources}} : {}; return apiService.get('/api/lbaas/pools/' + id + '/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve pool.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.createPool * @description * Create a new pool * @param {object} spec * Specifies the data used to create the new pool. */ function createPool(spec) { return apiService.post('/api/lbaas/pools/', spec) .catch(function () { toastService.add('error', gettext('Unable to create pool.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.editPool * @description * Edit a pool * @param {string} id * Specifies the id of the pool to update. * @param {object} spec * Specifies the data used to update the pool. */ function editPool(id, spec) { return apiService.put('/api/lbaas/pools/' + id + '/', spec) .catch(function () { toastService.add('error', gettext('Unable to update pool.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.deletePool * @description * Delete a single pool by ID * @param {string} id * Specifies the id of the pool to delete. * @param {boolean} quiet */ function deletePool(id, quiet) { var promise = apiService.delete('/api/lbaas/pools/' + id + '/'); return quiet ? promise : promise.catch(function () { toastService.add('error', gettext('Unable to delete pool.')); }); } // L7 Policies /** * @name horizon.app.core.openstack-service-api.lbaasv2.getL7Policies * @description * Get the list of l7 policies. * If a listener ID is passed as a parameter, the returning list of * l7 policies will be filtered to include only those l7 policies under the * specified listener. * @param {string} listenerId * Specifies the id of the listener to request l7policies for. * * The listing result is an object with property "items". Each item is * a l7 policy. */ function getL7Policies(listenerId) { var params = $.extend({}, { listenerId: listenerId } ); if (!$.isEmptyObject(params)) { params = { params: params }; } return apiService.get('/api/lbaas/l7policies/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve l7 policies.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.getL7Policy * @description * Get a single L7Policy by ID. * @param {string} id * Specifies the id of the l7 policy to request. * @param {boolean} includeChildResources * If truthy, all child resources below the l7 policy will be included in the response. */ function getL7Policy(id, includeChildResources) { var params = includeChildResources ? {params: {includeChildResources: includeChildResources}} : {}; return apiService.get('/api/lbaas/l7policies/' + id + '/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve l7 policy.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.createL7Policy * @description * Create a new l7 policy * @param {object} spec * Specifies the data used to create the new l7 policy. */ function createL7Policy(spec) { return apiService.post('/api/lbaas/l7policies/', spec) .catch(function () { toastService.add('error', gettext('Unable to create l7 policy.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.editL7Policy * @description * Edit a l7 policy * @param {string} id * Specifies the id of the l7 policy to update. * @param {object} spec * Specifies the data used to update the l7 policy. */ function editL7Policy(id, spec) { return apiService.put('/api/lbaas/l7policies/' + id + '/', spec) .catch(function () { toastService.add('error', gettext('Unable to update l7 policy.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.deleteL7Policy * @description * Delete a single l7 policy by ID * @param {string} id * Specifies the id of the l7 policy to delete. * @param {boolean} quiet */ function deleteL7Policy(id, quiet) { var promise = apiService.delete('/api/lbaas/l7policies/' + id + '/'); return quiet ? promise : promise.catch(function () { toastService.add('error', gettext('Unable to delete l7 policy.')); }); } // L7 Rules /** * @name horizon.app.core.openstack-service-api.lbaasv2.getL7Rules * @description * Get the list of l7 rules under the specified l7 policy. * @param {string} l7policyId * Specifies the id of the l7 policy to request l7rules for. * * The listing result is an object with property "items". * Each item is a l7 rule. */ function getL7Rules(l7policyId) { return apiService.get('/api/lbaas/l7policies/' + l7policyId + '/l7rules/') .catch(function () { toastService.add('error', gettext('Unable to retrieve l7 rules.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.getL7Rule * @description * Get a single L7Rule by ID. * @param {string} l7policyId * Specifies the id of the l7 policy the l7 rule belongs to. * @param {string} l7ruleId * Specifies the id of the l7 rule to request. */ function getL7Rule(l7policyId, l7ruleId) { return apiService.get('/api/lbaas/l7policies/' + l7policyId + '/l7rules/' + l7ruleId + '/') .catch(function () { toastService.add('error', gettext('Unable to retrieve l7 rule.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.createL7Rule * @description * Create a new l7 rule * @param {string} l7policyId * Specifies the id of the l7 policy the l7 rule belongs to. * @param {object} spec * Specifies the data used to create the new l7 rule. */ function createL7Rule(l7policyId, spec) { return apiService.post('/api/lbaas/l7policies/' + l7policyId + '/l7rules/', spec) .catch(function () { toastService.add('error', gettext('Unable to create l7 rule.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.editL7Rule * @description * Edit a l7 rule * @param {string} l7policyId * Specifies the id of the l7 policy the l7 rule belongs to. * @param {string} l7ruleId * Specifies the id of the l7 rule to update. * @param {object} spec * Specifies the data used to update the l7 rule. */ function editL7Rule(l7policyId, l7ruleId, spec) { return apiService.put('/api/lbaas/l7policies/' + l7policyId + '/l7rules/' + l7ruleId + '/', spec) .catch(function () { toastService.add('error', gettext('Unable to update l7 rule.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.deleteL7Rule * @description * Delete a single l7 rule by ID * @param {string} l7policyId * Specifies the id of the l7 policy the l7 rule belongs to. * @param {string} l7ruleId * Specifies the id of the l7 rule to delete. * @param {boolean} quiet */ function deleteL7Rule(l7policyId, l7ruleId, quiet) { var promise = apiService.delete('/api/lbaas/l7policies/' + l7policyId + '/l7rules/' + l7ruleId + '/'); return quiet ? promise : promise.catch(function () { toastService.add('error', gettext('Unable to delete l7 rule.')); }); } // Members /** * @name horizon.app.core.openstack-service-api.lbaasv2.getMembers * @description * Get a list of members. * @param {string} poolId * Specifies the id of the pool the members belong to. * * The listing result is an object with property "items". Each item is * a member. */ function getMembers(poolId) { return apiService.get('/api/lbaas/pools/' + poolId + '/members/') .catch(function () { toastService.add('error', gettext('Unable to retrieve members.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.getMember * @description * Get a single pool Member by ID. * @param {string} poolId * Specifies the id of the pool the member belongs to. * @param {string} memberId * Specifies the id of the member to request. */ function getMember(poolId, memberId) { return apiService.get('/api/lbaas/pools/' + poolId + '/members/' + memberId + '/') .catch(function () { toastService.add('error', gettext('Unable to retrieve member.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.deleteMember * @description * Delete a single pool Member by ID. * @param {string} poolId * Specifies the id of the pool the member belongs to. * @param {string} memberId * Specifies the id of the member to request. */ function deleteMember(poolId, memberId) { return apiService.delete('/api/lbaas/pools/' + poolId + '/members/' + memberId + '/') .catch(function () { toastService.add('error', gettext('Unable to delete member.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.editMember * @description * Edit a pool member. * @param {string} id * Specifies the id of the member to update. * @param {object} spec * Specifies the data used to update the member. */ function editMember(poolId, memberId, spec) { return apiService.put('/api/lbaas/pools/' + poolId + '/members/' + memberId + '/', spec) .catch(function () { toastService.add('error', gettext('Unable to update member.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.updateMemberList * @description * Update the list of pool members by adding or removing the necessary members. * @param {string} poolId * Specifies the id of the pool the members belong to. * @param {object} spec * Specifies the data used to update the member list. */ function updateMemberList(poolId, spec) { return apiService.put('/api/lbaas/pools/' + poolId + '/members/', spec) .catch(function () { toastService.add('error', gettext('Unable to update member list.')); }); } // Health Monitors /** * @name horizon.app.core.openstack-service-api.lbaasv2.getHealthMonitor * @description * Get a single pool health monitor by ID. * @param {string} monitorId * Specifies the id of the health monitor. */ /** * @name horizon.app.core.openstack-service-api.lbaasv2.getHealthMonitors * @description * Get the list of healthmonitors. * If a pool ID is passed as a parameter, the returning list of * healthmonitors will be filtered to include only those healthmonitors under the * specified pool. * @param {string} id * Specifies the id of the pool to request healthmonitors for. * * The listing result is an object with property "items". Each item is * a healthmonitor. */ function getHealthMonitors(id) { var params = id ? {params: {poolId: id}} : {}; return apiService.get('/api/lbaas/healthmonitors/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve health monitors.')); }); } function getHealthMonitor(monitorId) { return apiService.get('/api/lbaas/healthmonitors/' + monitorId + '/') .catch(function () { toastService.add('error', gettext('Unable to retrieve health monitor.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.editHealthMonitor * @description * Edit a health monitor * @param {string} id * Specifies the id of the health monitor to update. * @param {object} spec * Specifies the data used to update the health monitor. */ function editHealthMonitor(id, spec) { return apiService.put('/api/lbaas/healthmonitors/' + id + '/', spec) .catch(function () { toastService.add('error', gettext('Unable to update health monitor.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.deleteHealthMonitor * @description * Delete a single health monitor by ID * @param {string} id * Specifies the id of the health monitor to delete. * @param {boolean} quiet */ function deleteHealthMonitor(id, quiet) { var promise = apiService.delete('/api/lbaas/healthmonitors/' + id + '/'); return quiet ? promise : promise.catch(function () { toastService.add('error', gettext('Unable to delete health monitor.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.createHealthMonitor * @description * Create a new health monitor * @param {object} spec * Specifies the data used to create the new health monitor. */ function createHealthMonitor(spec) { return apiService.post('/api/lbaas/healthmonitors/', spec) .catch(function () { toastService.add('error', gettext('Unable to create health monitor.')); }); } // Flavors /** * @name horizon.app.core.openstack-service-api.lbaasv2.getFlavor * @description * Get a single load balancer flavor by ID. * @param {string} flavorId * Specifies the id of the flavor. */ /** * @name horizon.app.core.openstack-service-api.lbaasv2.getFlavors * @description * Get the list of flavors. * * The listing result is an object with property "items". Each item is * a flavor. */ function getFlavors() { var params = {params: {}}; return apiService.get('/api/lbaas/flavors/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve flavors.')); }); } function getFlavor(flavorId) { return apiService.get('/api/lbaas/flavors/' + flavorId + '/') .catch(function () { toastService.add('error', gettext('Unable to retrieve flavor.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.editFlavor * @description * Edit a flavor * @param {string} id * Specifies the id of the flavor to update. * @param {object} spec * Specifies the data used to update the flavor. */ function editFlavor(id, spec) { return apiService.put('/api/lbaas/flavors/' + id + '/', spec) .catch(function () { toastService.add('error', gettext('Unable to update flavor.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.deleteFlavor * @description * Delete a single flavor by ID * @param {string} id * Specifies the id of the flavor to delete. * @param {boolean} quiet */ function deleteFlavor(id, quiet) { var promise = apiService.delete('/api/lbaas/flavors/' + id + '/'); return quiet ? promise : promise.catch(function () { toastService.add('error', gettext('Unable to delete flavor.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.createFlavor * @description * Create a new flavor * @param {object} spec * Specifies the data used to create the new flavor. */ function createFlavor(spec) { return apiService.post('/api/lbaas/flavors/', spec) .catch(function () { toastService.add('error', gettext('Unable to create flavor.')); }); } // Flavor Profiles /** * @name horizon.app.core.openstack-service-api.lbaasv2.getFlavorProfile * @description * Get a single load balancer flavor profile by ID. * @param {string} flavorProfileId * Specifies the id of the flavor profile. */ /** * @name horizon.app.core.openstack-service-api.lbaasv2.getFlavorProfiles * @description * Get the list of flavor profiles. * * The listing result is an object with property "items". Each item is * a flavor profile. */ function getFlavorProfiles() { var params = {params: {}}; return apiService.get('/api/lbaas/flavorprofiles/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve flavor profiles.')); }); } function getFlavorProfile(flavorProfileId) { return apiService.get('/api/lbaas/flavorprofiles/' + flavorProfileId + '/') .catch(function () { toastService.add('error', gettext('Unable to retrieve flavor profile.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.editFlavorProfile * @description * Edit a flavor Profile * @param {string} id * Specifies the id of the flavor profile to update. * @param {object} spec * Specifies the data used to update the flavor profile. */ function editFlavorProfile(id, spec) { return apiService.put('/api/lbaas/flavorprofiles/' + id + '/', spec) .catch(function () { toastService.add('error', gettext('Unable to update flavor profile.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.deleteFlavorProfile * @description * Delete a single flavor profile by ID * @param {string} id * Specifies the id of the flavor profile to delete. * @param {boolean} quiet */ function deleteFlavorProfile(id, quiet) { var promise = apiService.delete('/api/lbaas/flavorprofiles/' + id + '/'); return quiet ? promise : promise.catch(function () { toastService.add('error', gettext('Unable to delete flavor profile.')); }); } /** * @name horizon.app.core.openstack-service-api.lbaasv2.createFlavorProfile * @description * Create a new flavor profile * @param {object} spec * Specifies the data used to create the new flavor profile. */ function createFlavorProfile(spec) { return apiService.post('/api/lbaas/flavorprofiles/', spec) .catch(function () { toastService.add('error', gettext('Unable to create flavor profile.')); }); } // Availability Zones /** * @name horizon.app.core.openstack-service-api.lbaasv2.getAvailabilityZones * @description * Get the list of availability zones. * * The listing result is an object with property "items". Each item is * an availability zone. */ function getAvailabilityZones() { var params = {params: {}}; return apiService.get('/api/lbaas/availabilityzones/', params) .catch(function () { toastService.add('error', gettext('Unable to retrieve availability zones.')); }); } } }()); ././@PaxHeader0000000000000000000000000000021500000000000010213 xustar00119 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.servic0000664000175100017510000003667215033037474032625 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 API', function() { var testCall, service; var apiService = {}; var toastService = {}; beforeEach(module('horizon.mock.openstack-service-api', function($provide, initServices) { testCall = initServices($provide, apiService, toastService); })); beforeEach(module('horizon.app.core.openstack-service-api')); beforeEach(inject(['horizon.app.core.openstack-service-api.lbaasv2', function(lbaasv2API) { service = lbaasv2API; }])); it('defines the service', function() { expect(service).toBeDefined(); }); var tests = [ { func: 'getLoadBalancers', method: 'get', path: '/api/lbaas/loadbalancers/', error: 'Unable to retrieve load balancers.', testInput: [ true ], data: { params: { full: true } } }, { func: 'getLoadBalancer', method: 'get', path: '/api/lbaas/loadbalancers/1234/', error: 'Unable to retrieve load balancer.', testInput: [ '1234', true ], data: { params: { full: true } } }, { func: 'deleteLoadBalancer', method: 'delete', path: '/api/lbaas/loadbalancers/1234/', error: 'Unable to delete load balancer.', testInput: [ '1234' ] }, { func: 'getListeners', method: 'get', path: '/api/lbaas/listeners/', error: 'Unable to retrieve listeners.', testInput: [ '1234' ], data: { params: { loadbalancerId: '1234' } } }, { func: 'getListeners', method: 'get', path: '/api/lbaas/listeners/', data: {}, error: 'Unable to retrieve listeners.' }, { func: 'getListener', method: 'get', path: '/api/lbaas/listeners/1234/', data: { params: { includeChildResources: true } }, error: 'Unable to retrieve listener.', testInput: [ '1234', true ] }, { func: 'getListener', method: 'get', path: '/api/lbaas/listeners/1234/', data: {}, error: 'Unable to retrieve listener.', testInput: [ '1234', false ] }, { func: 'getL7Policies', method: 'get', path: '/api/lbaas/l7policies/', error: 'Unable to retrieve l7 policies.', testInput: [ '1234' ], data: { params: { listenerId: '1234' } } }, { func: 'getL7Policies', method: 'get', path: '/api/lbaas/l7policies/', data: {}, error: 'Unable to retrieve l7 policies.' }, { func: 'getL7Policy', method: 'get', path: '/api/lbaas/l7policies/1234/', data: { params: { includeChildResources: true } }, error: 'Unable to retrieve l7 policy.', testInput: [ '1234', true ] }, { func: 'getL7Policy', method: 'get', path: '/api/lbaas/l7policies/1234/', data: {}, error: 'Unable to retrieve l7 policy.', testInput: [ '1234', false ] }, { func: 'deleteL7Policy', method: 'delete', path: '/api/lbaas/l7policies/1234/', error: 'Unable to delete l7 policy.', testInput: [ '1234' ] }, { func: 'getL7Rules', method: 'get', path: '/api/lbaas/l7policies/1234/l7rules/', error: 'Unable to retrieve l7 rules.', testInput: [ '1234' ] }, { func: 'getL7Rule', method: 'get', path: '/api/lbaas/l7policies/1234/l7rules/5678/', error: 'Unable to retrieve l7 rule.', testInput: [ '1234', '5678' ] }, { func: 'deleteL7Rule', method: 'delete', path: '/api/lbaas/l7policies/1234/l7rules/5678/', error: 'Unable to delete l7 rule.', testInput: [ '1234', '5678' ] }, { func: 'getPools', method: 'get', path: '/api/lbaas/pools/', error: 'Unable to retrieve pools.', testInput: [ '1234' ], data: { params: { loadbalancerId: '1234' } } }, { func: 'getPools', method: 'get', path: '/api/lbaas/pools/', error: 'Unable to retrieve pools.', testInput: [ '1234', '5678' ], data: { params: { loadbalancerId: '1234', listenerId: '5678' } } }, { func: 'getPools', method: 'get', path: '/api/lbaas/pools/', error: 'Unable to retrieve pools.', testInput: [ undefined, '5678' ], data: { params: { listenerId: '5678' } } }, { func: 'getPools', method: 'get', path: '/api/lbaas/pools/', data: {}, error: 'Unable to retrieve pools.' }, { func: 'getPool', method: 'get', path: '/api/lbaas/pools/1234/', data: { params: { includeChildResources: true } }, error: 'Unable to retrieve pool.', testInput: [ '1234', true ] }, { func: 'getPool', method: 'get', path: '/api/lbaas/pools/1234/', data: {}, error: 'Unable to retrieve pool.', testInput: [ '1234', false ] }, { func: 'deletePool', method: 'delete', path: '/api/lbaas/pools/1234/', error: 'Unable to delete pool.', testInput: [ '1234' ] }, { func: 'getMembers', method: 'get', path: '/api/lbaas/pools/1234/members/', error: 'Unable to retrieve members.', testInput: [ '1234' ] }, { func: 'getMember', method: 'get', path: '/api/lbaas/pools/1234/members/5678/', error: 'Unable to retrieve member.', testInput: [ '1234', '5678' ] }, { func: 'deleteMember', method: 'delete', path: '/api/lbaas/pools/1234/members/5678/', error: 'Unable to delete member.', testInput: [ '1234', '5678' ] }, { func: 'editMember', method: 'put', path: '/api/lbaas/pools/1234/members/5678/', error: 'Unable to update member.', data: { weight: 2 }, testInput: [ '1234', '5678', { weight: 2 } ] }, { func: 'getHealthMonitors', method: 'get', path: '/api/lbaas/healthmonitors/', error: 'Unable to retrieve health monitors.', testInput: [ '1234' ], data: { params: { poolId: '1234' } } }, { func: 'getHealthMonitors', method: 'get', path: '/api/lbaas/healthmonitors/', data: {}, error: 'Unable to retrieve health monitors.' }, { func: 'getHealthMonitor', method: 'get', path: '/api/lbaas/healthmonitors/1234/', error: 'Unable to retrieve health monitor.', testInput: [ '1234' ] }, { func: 'editHealthMonitor', method: 'put', path: '/api/lbaas/healthmonitors/1234/', error: 'Unable to update health monitor.', data: { name: 'healthmonitor-1' }, testInput: [ '1234', { name: 'healthmonitor-1' } ] }, { func: 'deleteHealthMonitor', method: 'delete', path: '/api/lbaas/healthmonitors/1234/', error: 'Unable to delete health monitor.', testInput: [ '1234' ] }, { func: 'getFlavors', method: 'get', path: '/api/lbaas/flavors/', error: 'Unable to retrieve flavors.', testInput: [], data: { params: {} } }, { func: 'getFlavor', method: 'get', path: '/api/lbaas/flavors/1234/', error: 'Unable to retrieve flavor.', testInput: [ '1234' ] }, { func: 'editFlavor', method: 'put', path: '/api/lbaas/flavors/1234/', error: 'Unable to update flavor.', data: { name: 'flavor-1' }, testInput: [ '1234', { name: 'flavor-1' } ] }, { func: 'deleteFlavor', method: 'delete', path: '/api/lbaas/flavors/1234/', error: 'Unable to delete flavor.', testInput: [ '1234' ] }, { func: 'getFlavorProfiles', method: 'get', path: '/api/lbaas/flavorprofiles/', error: 'Unable to retrieve flavor profiles.', testInput: [], data: { params: {} } }, { func: 'getFlavorProfile', method: 'get', path: '/api/lbaas/flavorprofiles/1234/', error: 'Unable to retrieve flavor profile.', testInput: [ '1234' ] }, { func: 'editFlavorProfile', method: 'put', path: '/api/lbaas/flavorprofiles/1234/', error: 'Unable to update flavor profile.', data: { name: 'flavorprofile-1' }, testInput: [ '1234', { name: 'flavorprofile-1' } ] }, { func: 'deleteFlavorProfile', method: 'delete', path: '/api/lbaas/flavorprofiles/1234/', error: 'Unable to delete flavor profile.', testInput: [ '1234' ] }, { func: 'getAvailabilityZones', method: 'get', path: '/api/lbaas/availabilityzones/', error: 'Unable to retrieve availability zones.', testInput: [], data: { params: {} } }, { func: 'createLoadBalancer', method: 'post', path: '/api/lbaas/loadbalancers/', error: 'Unable to create load balancer.', data: { name: 'loadbalancer-1' }, testInput: [ { name: 'loadbalancer-1' } ] }, { func: 'editLoadBalancer', method: 'put', path: '/api/lbaas/loadbalancers/1234/', error: 'Unable to update load balancer.', data: { name: 'loadbalancer-1' }, testInput: [ '1234', { name: 'loadbalancer-1' } ] }, { func: 'createListener', method: 'post', path: '/api/lbaas/listeners/', error: 'Unable to create listener.', data: { name: 'listener-1' }, testInput: [ { name: 'listener-1' } ] }, { func: 'editListener', method: 'put', path: '/api/lbaas/listeners/1234/', error: 'Unable to update listener.', data: { name: 'listener-1' }, testInput: [ '1234', { name: 'listener-1' } ] }, { func: 'deleteListener', method: 'delete', path: '/api/lbaas/listeners/1234/', error: 'Unable to delete listener.', testInput: [ '1234' ] }, { func: 'createL7Policy', method: 'post', path: '/api/lbaas/l7policies/', error: 'Unable to create l7 policy.', data: { name: 'l7policy-1' }, testInput: [ { name: 'l7policy-1' } ] }, { func: 'editL7Policy', method: 'put', path: '/api/lbaas/l7policies/1234/', error: 'Unable to update l7 policy.', data: { name: 'l7policy-1' }, testInput: [ '1234', { name: 'l7policy-1' } ] }, { func: 'createL7Rule', method: 'post', path: '/api/lbaas/l7policies/1234/l7rules/', error: 'Unable to create l7 rule.', data: { name: 'l7rule-1' }, testInput: [ '1234', { name: 'l7rule-1' } ] }, { func: 'editL7Rule', method: 'put', path: '/api/lbaas/l7policies/1234/l7rules/5678/', error: 'Unable to update l7 rule.', data: { name: 'l7rule-1' }, testInput: [ '1234', '5678', { name: 'l7rule-1' } ] }, { func: 'createPool', method: 'post', path: '/api/lbaas/pools/', error: 'Unable to create pool.', data: { name: 'pool-1' }, testInput: [ { name: 'pool-1' } ] }, { func: 'editPool', method: 'put', path: '/api/lbaas/pools/1234/', error: 'Unable to update pool.', data: { name: 'pool-1' }, testInput: [ '1234', { name: 'pool-1' } ] }, { func: 'createHealthMonitor', method: 'post', path: '/api/lbaas/healthmonitors/', error: 'Unable to create health monitor.', data: { name: 'healthmonitor-1' }, testInput: [ { name: 'healthmonitor-1' } ] }, { func: 'createFlavor', method: 'post', path: '/api/lbaas/flavors/', error: 'Unable to create flavor.', data: { name: 'flavor-1' }, testInput: [ { name: 'flavor-1' } ] }, { func: 'createFlavorProfile', method: 'post', path: '/api/lbaas/flavorprofiles/', error: 'Unable to create flavor profile.', data: { name: 'flavorprofile-1' }, testInput: [ { name: 'flavorprofile-1' } ] }, { func: 'updateMemberList', method: 'put', path: '/api/lbaas/pools/1234/members/', error: 'Unable to update member list.', data: { name: 'member-1' }, testInput: [ '1234', { name: 'member-1' } ] } ]; // Iterate through the defined tests and apply as Jasmine specs. angular.forEach(tests, function(params) { it('defines the ' + params.func + ' call properly', function() { var callParams = [apiService, service, toastService, params]; testCall.apply(this, callParams); }); }); it('supresses the error if instructed for deleteLoadBalancer', function() { spyOn(apiService, 'delete').and.returnValue("promise"); expect(service.deleteLoadBalancer("whatever", true)).toBe("promise"); }); it('supresses the error if instructed for deleteListener', function() { spyOn(apiService, 'delete').and.returnValue("promise"); expect(service.deleteListener("whatever", true)).toBe("promise"); }); it('supresses the error if instructed for deleteL7Policy', function() { spyOn(apiService, 'delete').and.returnValue("promise"); expect(service.deleteL7Policy("whatever", true)).toBe("promise"); }); it('supresses the error if instructed for deleteL7Rule', function() { spyOn(apiService, 'delete').and.returnValue("promise"); expect(service.deleteL7Rule("whatever", "whatever", true)).toBe("promise"); }); it('supresses the error if instructed for deletePool', function() { spyOn(apiService, 'delete').and.returnValue("promise"); expect(service.deletePool("whatever", true)).toBe("promise"); }); it('supresses the error if instructed for deleteHealthMonitor', function() { spyOn(apiService, 'delete').and.returnValue("promise"); expect(service.deleteHealthMonitor("whatever", true)).toBe("promise"); }); it('supresses the error if instructed for deleteFlavor', function() { spyOn(apiService, 'delete').and.returnValue("promise"); expect(service.deleteFlavor("whatever", true)).toBe("promise"); }); it('supresses the error if instructed for deleteFlavorProfile', function() { spyOn(apiService, 'delete').and.returnValue("promise"); expect(service.deleteFlavorProfile("whatever", true)).toBe("promise"); }); }); })(); ././@PaxHeader0000000000000000000000000000022100000000000010210 xustar00123 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/openstack-service-api/octavia-barbican.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/openstack-service-api/octavia-barbic0000664000175100017510000000512115033037474032630 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.app.core.openstack-service-api') .factory('horizon.app.core.openstack-service-api.octavia-barbican', octaviaBarbicanAPI); octaviaBarbicanAPI.$inject = [ 'horizon.framework.util.http.service', 'horizon.framework.widgets.toast.service' ]; /** * @ngdoc service * @name horizon.app.core.openstack-service-api.octavia-barbican * @description Provides direct pass through to barbican with NO abstraction. * @param apiService The horizon core API service. * @param toastService The horizon toast service. * @returns The octavia barbican service API. */ function octaviaBarbicanAPI(apiService, toastService) { var service = { getCertificates: getCertificates, getSecrets: getSecrets }; return service; /////////////// // SSL Certificate Containers /** * @name horizon.app.core.openstack-service-api.octavia-barbican.getCertificates * @description * Get a list of SSL certificate containers. * * @param {boolean} quiet * The listing result is an object with property "items". Each item is * a certificate container. */ function getCertificates(quiet) { var promise = apiService.get('/api/octavia-barbican/certificates/'); return quiet ? promise : promise.catch(function handleError() { toastService.add('error', gettext('Unable to retrieve SSL certificates.')); }); } // Secrets /** * @name horizon.app.core.openstack-service-api.octavia-barbican.getSecrets * @description * Get a list of secrets. * * @param {boolean} quiet * The listing result is an object with property "items". Each item is * a secret. */ function getSecrets(quiet) { var promise = apiService.get('/api/octavia-barbican/secrets/'); return quiet ? promise : promise.catch(function handleError() { toastService.add('error', gettext('Unable to retrieve secrets.')); }); } } }()); ././@PaxHeader0000000000000000000000000000022600000000000010215 xustar00128 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/openstack-service-api/octavia-barbican.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/app/core/openstack-service-api/octavia-barbic0000664000175100017510000000451215033037474032633 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function() { 'use strict'; describe('Barbican API', function() { var testCall, service; var apiService = {}; var toastService = {}; beforeEach(module('horizon.mock.openstack-service-api', function($provide, initServices) { testCall = initServices($provide, apiService, toastService); })); beforeEach(module('horizon.app.core.openstack-service-api')); beforeEach( inject(['horizon.app.core.openstack-service-api.octavia-barbican', function(octaviaBarbicanAPI) { service = octaviaBarbicanAPI; }])); it('defines the service', function() { expect(service).toBeDefined(); }); var tests = [ { func: "getCertificates", method: "get", path: "/api/octavia-barbican/certificates/", error: "Unable to retrieve SSL certificates." }, { func: "getSecrets", method: "get", path: "/api/octavia-barbican/secrets/", error: "Unable to retrieve secrets." } ]; // Iterate through the defined tests and apply as Jasmine specs. angular.forEach(tests, function(params) { it('defines the ' + params.func + ' call properly', function() { var callParams = [apiService, service, toastService, params]; testCall.apply(this, callParams); }); }); it('supresses the error if instructed for getCertificates', function() { spyOn(apiService, 'get').and.returnValue("promise"); expect(service.getCertificates(true)).toBe("promise"); }); it('supresses the error if instructed for getSecrets', function() { spyOn(apiService, 'get').and.returnValue("promise"); expect(service.getSecrets(true)).toBe("promise"); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4541008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/0000775000175100017510000000000015033037476024065 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4541008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/0000775000175100017510000000000015033037476025533 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4671009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/0000775000175100017510000000000015033037476027065 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4671009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/0000775000175100017510000000000015033037476032125 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00114 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/ 28 mtime=1751924542.4541008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000775000175100017510000000000015033037476032766 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022500000000000010214 xustar00121 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/ 28 mtime=1751924542.4671009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000775000175100017510000000000015033037476032766 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024700000000000010220 xustar00145 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/create.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000000447415033037474032777 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.healthmonitors') .factory('horizon.dashboard.project.lbaasv2.healthmonitors.actions.create', createService); createService.$inject = [ 'horizon.dashboard.project.lbaasv2.healthmonitors.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.healthmonitors.actions.createService * * @description * Provides the service for creating a health monitor resource. * * @param resourceType The health monitor resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns The health monitor create service. */ function createService(resourceType, actionResultService, workflowModal, policy, gettext) { return workflowModal.init({ controller: 'CreateHealthMonitorWizardController', message: gettext('A new health monitor is being created.'), handle: handle, allowed: allowed }); function allowed() { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:healthmonitor:post']] }); } function handle(response) { var newHealthMonitor = response.data; return actionResultService.getActionResult() .created(resourceType, newHealthMonitor.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000025400000000000010216 xustar00150 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/create.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000000306615033037474032773 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Create Health Monitor Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.healthmonitors.actions.create'); })); it('should check policy to allow creating a health monitor', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); expect(service.allowed()).toBe(true); expect(policy.ifAllowed) .toHaveBeenCalledWith({ rules: [[ 'load-balancer', 'os_load-balancer_api:healthmonitor:post' ]] }); }); it('should handle the action result properly', function() { var result = service.handle({data: {id: 1}}); expect(result.created[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000024300000000000010214 xustar00141 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000000301715033037474032767 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.healthmonitors') .controller('CreateHealthMonitorWizardController', CreateHealthMonitorWizardController); CreateHealthMonitorWizardController.$inject = [ '$scope', '$routeParams', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; function CreateHealthMonitorWizardController( $scope, $routeParams, model, workflowService, gettext ) { var loadbalancerId = $routeParams.loadbalancerId; var poolId = $routeParams.poolId; var scope = $scope; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Create Health Monitor'), 'fa fa-cloud-download', ['monitor'] ); scope.model.initialize('monitor', false, loadbalancerId, poolId); } })(); ././@PaxHeader0000000000000000000000000000025000000000000010212 xustar00146 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000000362015033037474032767 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Create Health Monitor Wizard Controller', function() { var ctrl; var model = { submit: function() { return 'created'; }, initialize: angular.noop }; var workflow = function() { return 'foo'; }; var scope = { launchContext: {id: 'pool1'} }; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow); })); beforeEach(inject(function ($controller) { spyOn(model, 'initialize'); ctrl = $controller('CreateHealthMonitorWizardController', { $scope: scope }); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalled(); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe('foo'); }); it('defines scope.submit', function() { expect(scope.submit).toBeDefined(); expect(scope.submit()).toBe('created'); }); }); })(); ././@PaxHeader0000000000000000000000000000022500000000000010214 xustar00121 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/delete/ 28 mtime=1751924542.4671009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000775000175100017510000000000015033037476032766 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024700000000000010220 xustar00145 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/delete/delete.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000001121715033037474032770 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.healthmonitors') .factory('horizon.dashboard.project.lbaasv2.healthmonitors.actions.delete', deleteService); deleteService.$inject = [ 'horizon.dashboard.project.lbaasv2.healthmonitors.resourceType', 'horizon.framework.util.actions.action-result.service', '$location', 'horizon.framework.widgets.modal.deleteModalService', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.framework.util.i18n.gettext', 'horizon.app.core.openstack-service-api.policy' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.healthmonitors.actions.deleteService * * @description * Brings up the delete health monitor confirmation modal dialog. * On submit, deletes selected health monitor. * On cancel, does nothing. * * @param resourceType The health monitor resource type. * @param actionResultService The horizon action result service. * @param $location The angular $location service. * @param deleteModal The horizon delete modal service. * @param api The LBaaS v2 API service. * @param gettext The horizon gettext function for translation. * @param policy The horizon policy service. * * @returns The health monitor delete service. */ function deleteService( resourceType, actionResultService, $location, deleteModal, api, gettext, policy ) { var loadbalancerId, listenerId, poolId; var service = { perform: perform, allowed: allowed, deleteResult: deleteResult // exposed just for testing }; return service; ////////////// function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:healthmonitor:delete']] }); } function perform(items, scope) { var context = { }; var healthMonitors = angular.isArray(items) ? items : [items]; context.labels = labelize(healthMonitors.length); context.deleteEntity = deleteItem; healthMonitors.map(function(item) { loadbalancerId = item.loadbalancerId; listenerId = item.listenerId; poolId = item.poolId; }); return deleteModal.open(scope, healthMonitors, context).then(deleteResult); } function labelize(count) { return { title: ngettext( 'Confirm Delete Health Monitor', 'Confirm Delete Health Monitors', count), message: ngettext( 'You have selected "%s". Deleted health monitor is not recoverable.', 'You have selected "%s". Deleted health monitors are not recoverable.', count), submit: ngettext( 'Delete Health Monitor', 'Delete Health Monitors', count), success: ngettext( 'Deleted Health Monitor: %s.', 'Deleted Health Monitors: %s.', count), error: ngettext( 'Unable to delete Health Monitor: %s.', 'Unable to delete Health Monitors: %s.', count) }; } function deleteResult(deleteModalResult) { // To make the result of this action generically useful, reformat the return // from the deleteModal into a standard form var actionResult = actionResultService.getActionResult(); deleteModalResult.pass.forEach(function markDeleted(item) { actionResult.deleted(resourceType, item.context.id); }); deleteModalResult.fail.forEach(function markFailed(item) { actionResult.failed(resourceType, item.context.id); }); if (actionResult.result.failed.length === 0 && actionResult.result.deleted.length > 0) { var path; if (listenerId) { path = 'project/load_balancer/' + loadbalancerId + '/listeners/' + listenerId + '/pools/' + poolId; } else { path = 'project/load_balancer/' + loadbalancerId + '/pools/' + poolId; } $location.path(path); } return actionResult.result; } function deleteItem(id) { return api.deleteHealthMonitor(id, true); } } })(); ././@PaxHeader0000000000000000000000000000025400000000000010216 xustar00150 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/delete/delete.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000001133215033037474032766 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Health Monitor Delete Service', function() { beforeEach(module('horizon.app.core')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module('horizon.framework')); var deleteModalService, service, lbaasv2API, policyAPI, $location; beforeEach(inject(function($injector) { service = $injector.get('horizon.dashboard.project.lbaasv2.healthmonitors.actions.delete'); lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); deleteModalService = $injector.get('horizon.framework.widgets.modal.deleteModalService'); policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy'); $location = $injector.get('$location'); })); describe('perform method', function() { beforeEach(function () { // just need for this to return something that looks like a promise but does nothing spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); }); it('should open the modal with correct label', function () { service.perform({name: 'spam'}); var labels = deleteModalService.open.calls.argsFor(0)[2].labels; expect(deleteModalService.open).toHaveBeenCalled(); angular.forEach(labels, function eachLabel(label) { expect(label.toLowerCase()).toContain('health monitor'); }); }); it('should open the delete modal with correct entities', function () { service.perform([{name: 'one'}, {name: 'two'}]); var entities = deleteModalService.open.calls.argsFor(0)[1]; expect(deleteModalService.open).toHaveBeenCalled(); expect(entities.length).toEqual(2); }); it('should pass in a function that deletes a health monitor', function () { spyOn(lbaasv2API, 'deleteHealthMonitor').and.callFake(angular.noop); service.perform({id: 1, name: 'one'}); var contextArg = deleteModalService.open.calls.argsFor(0)[2]; var deleteFunction = contextArg.deleteEntity; deleteFunction(1); expect(lbaasv2API.deleteHealthMonitor).toHaveBeenCalledWith(1, true); }); }); it('should handle the action result properly with listener', function() { spyOn($location, 'path'); spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); spyOn(lbaasv2API, 'deleteHealthMonitor').and.callFake(angular.noop); service.perform({loadbalancerId: 1, listenerId: 2, poolId: 3, id: 1, name: 'one'}); var result = service.deleteResult({ fail: [], pass: [{ context: { id: 1 } }] }); var path = 'project/load_balancer/1/listeners/2/pools/3'; expect($location.path).toHaveBeenCalledWith(path); expect(result.deleted[0].id).toBe(1); result = service.deleteResult({ pass: [], fail: [{ context: { id: 1 } }] }); expect(result.failed[0].id).toBe(1); }); it('should handle the action result properly without listener', function() { spyOn($location, 'path'); spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); spyOn(lbaasv2API, 'deleteHealthMonitor').and.callFake(angular.noop); service.perform({loadbalancerId: 1, poolId: 3, id: 1, name: 'one'}); var result = service.deleteResult({ fail: [], pass: [{ context: { id: 1 } }] }); var path = 'project/load_balancer/1/pools/3'; expect($location.path).toHaveBeenCalledWith(path); expect(result.deleted[0].id).toBe(1); result = service.deleteResult({ pass: [], fail: [{ context: { id: 1 } }] }); expect(result.failed[0].id).toBe(1); }); describe('allow method', function() { it('should use default policy if batch action', function () { spyOn(policyAPI, 'ifAllowed'); service.allowed(); expect(policyAPI.ifAllowed).toHaveBeenCalled(); }); }); // end of allowed }); // end of delete })(); ././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00119 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/ 28 mtime=1751924542.4671009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000775000175100017510000000000015033037476032766 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024300000000000010214 xustar00141 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000000443415033037474032773 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.healthmonitors') .factory('horizon.dashboard.project.lbaasv2.healthmonitors.actions.edit', editService); editService.$inject = [ 'horizon.dashboard.project.lbaasv2.healthmonitors.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.healthmonitors.actions.editService * * @description * Provides the service for editing a health monitor resource. * * @param resourceType The health monitor resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns The health monitor edit service. */ function editService(resourceType, actionResultService, workflowModal, policy, gettext) { return workflowModal.init({ controller: 'EditHealthMonitorWizardController', message: gettext('The health monitor has been updated.'), handle: handle, allowed: allowed }); function allowed(/*healthmonitor*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:healthmonitor:put']] }); } function handle(response) { return actionResultService.getActionResult() .updated(resourceType, response.config.data.monitor.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000025000000000000010212 xustar00146 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000000310515033037474032765 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Edit Health Monitor Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.healthmonitors.actions.edit'); })); it('should check policy to allow editing a health monitor', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); expect(service.allowed()).toBe(true); expect(policy.ifAllowed) .toHaveBeenCalledWith({ rules: [[ 'load-balancer', 'os_load-balancer_api:healthmonitor:put' ]] }); }); it('should handle the action result properly', function() { var result = service.handle({config: {data: {monitor: {id: 1}}}}); expect(result.updated[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000024100000000000010212 xustar00139 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000000257215033037474032774 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.healthmonitors') .controller('EditHealthMonitorWizardController', EditHealthMonitorWizardController); EditHealthMonitorWizardController.$inject = [ '$scope', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; function EditHealthMonitorWizardController($scope, model, workflowService, gettext) { var scope = $scope; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Update Health Monitor'), 'fa fa-cloud-download', ['monitor'] ); scope.model.initialize('monitor', scope.launchContext.id); } })(); ././@PaxHeader0000000000000000000000000000024600000000000010217 xustar00144 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000664000175100017510000000362515033037474032774 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Edit Health Monitor Wizard Controller', function() { var ctrl; var model = { submit: function() { return 'updated'; }, initialize: angular.noop }; var workflow = function() { return 'foo'; }; var scope = { launchContext: {id: 'healthmonitor1'} }; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow); })); beforeEach(inject(function ($controller) { spyOn(model, 'initialize'); ctrl = $controller('EditHealthMonitorWizardController', { $scope: scope }); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalled(); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe('foo'); }); it('defines scope.submit', function() { expect(scope.submit).toBeDefined(); expect(scope.submit()).toBe('updated'); }); }); })(); ././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00114 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/ 28 mtime=1751924542.4671009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000775000175100017510000000000015033037476032763 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00134 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/detail.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000664000175100017510000001167215033037474032772 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.healthmonitors') .controller('HealthMonitorDetailController', HealthMonitorDetailController); HealthMonitorDetailController.$inject = [ '$timeout', 'horizon.dashboard.project.lbaasv2.events', '$scope', 'loadbalancer', 'listener', 'pool', 'healthmonitor', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.healthmonitors.resourceType', 'horizon.framework.conf.resource-type-registry.service', 'horizon.framework.widgets.modal-wait-spinner.service', '$q' ]; /** * @ngdoc controller * @name HealthMonitorDetailController * * @description * Controller for the LBaaS v2 health monitor detail page. * * @param $timeout The angular timeout object. * @param events The LBaaS v2 events object. * @param $scope The angular scope object. * @param loadbalancer The loadbalancer object. * @param listener The listener object. * @param pool The pool object. * @param healthmonitor The health monitor object. * @param loadBalancersService The LBaaS v2 load balancers service. * @param resourceType The health monitor resource type. * @param typeRegistry The horizon resource type registry service. * @param spinnerService The horizon modal wait spinner service. * @param $q The angular service for promises. * * @returns undefined */ function HealthMonitorDetailController( $timeout, events, $scope, loadbalancer, listener, pool, healthmonitor, loadBalancersService, resourceType, typeRegistry, spinnerService, $q ) { var ctrl = this; ctrl.operatingStatus = loadBalancersService.operatingStatus; ctrl.provisioningStatus = loadBalancersService.provisioningStatus; ctrl.loadbalancer = loadbalancer; ctrl.listener = listener; if (!angular.equals({}, ctrl.listener)) { ctrl.withListenerStyle = {}; ctrl.withoutListenerStyle = {display: 'none'}; } else { ctrl.withListenerStyle = {display: 'none'}; ctrl.withoutListenerStyle = {}; } ctrl.pool = pool; ctrl.healthmonitor = healthmonitor; ctrl.resourceType = typeRegistry.getResourceType(resourceType); ctrl.context = {}; ctrl.context.identifier = ctrl.resourceType.parsePath(ctrl.healthmonitor.id); ctrl.resultHandler = actionResultHandler; $scope.$watch( function() { return ctrl.healthmonitor; }, function() { $timeout.cancel($scope.loadTimeout); $scope.loadTimeout = $timeout(function() { ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); }, loadBalancersService.backoff.duration()); } ); $scope.$on( events.ACTION_DONE, function() { loadBalancersService.backoff.reset(); } ); $scope.$on( '$destroy', function() { $timeout.cancel($scope.loadTimeout); } ); function actionResultHandler(returnValue) { return $q.when(returnValue, actionSuccessHandler); } function loadData(response) { spinnerService.hideModalSpinner(); ctrl.showDetails = true; ctrl.resourceType.initActions(); ctrl.healthmonitor = response.data; ctrl.healthmonitor.loadbalancerId = ctrl.loadbalancer.id; ctrl.healthmonitor.listenerId = ctrl.listener.id; ctrl.healthmonitor.poolId = ctrl.pool.id; } function actionSuccessHandler(result) { // The action has completed (for whatever "complete" means to that // action. Notice the view doesn't really need to know the semantics of the // particular action because the actions return data in a standard form. // That return includes the id and type of each created, updated, deleted // and failed item. // Currently just refreshes the display each time. if (result) { if (result.failed.length === 0 && result.deleted.length > 0) { // handle a race condition where the resource is already deleted return; } spinnerService.showModalSpinner(gettext('Please Wait')); ctrl.showDetails = false; ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); } } } })(); ././@PaxHeader0000000000000000000000000000024100000000000010212 xustar00139 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/detail.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000664000175100017510000001241215033037474032763 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 HealthMonitor Detail Controller', function() { var deferred, service, ctrl, scope, $timeout, $q, actionResultService; /////////////////////// beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModal', {}); })); beforeEach(inject(function($controller, $rootScope, _$q_, _$timeout_) { $q = _$q_; deferred = $q.defer(); service = { getResourceType: function() { return { load: function() { return deferred.promise; }, parsePath: function() { return 'my-context'; }, itemName: function() { return 'A name'; }, initActions: angular.noop }; }, getDefaultDetailsTemplateUrl: angular.noop }; actionResultService = { getIdsOfType: function() { return []; } }; $timeout = _$timeout_; scope = $rootScope.$new(); ctrl = $controller('HealthMonitorDetailController', { $scope: scope, loadbalancer: { id: '123' }, listener: {}, pool: { id: '123' }, healthmonitor: { id: '123', provisioning_status: 'ACTIVE' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); ctrl = $controller('HealthMonitorDetailController', { $scope: scope, loadbalancer: { id: '123' }, listener: { id: '123' }, pool: { id: '123' }, healthmonitor: { id: '123', provisioning_status: 'ACTIVE' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); })); it('should create a controller', function() { expect(ctrl).toBeDefined(); expect(ctrl.loadbalancer).toBeDefined(); expect(ctrl.listener).toBeDefined(); expect(ctrl.pool).toBeDefined(); expect(ctrl.healthmonitor).toBeDefined(); }); describe('data watchers', function() { var events, loadBalancersService; beforeEach(inject(function($injector) { events = $injector.get('horizon.dashboard.project.lbaasv2.events'); loadBalancersService = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.service' ); })); it('should refresh on provisioning status change', function() { var loadFunctionDeferred = $q.defer(); spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise); ctrl.healthmonitor = { id: '123', provisioning_status: 'PENDING_UPDATE' }; scope.$apply(); $timeout.flush(); expect(ctrl.resourceType.load).toHaveBeenCalled(); spyOn(loadBalancersService.backoff, 'reset').and.callThrough(); scope.$broadcast(events.ACTION_DONE); expect(loadBalancersService.backoff.reset).toHaveBeenCalled(); }); }); describe('resultHandler', function() { it('handles empty results', function() { var result = $q.defer(); result.resolve({failed: [], deleted: []}); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles falsy results', function() { var result = $q.defer(); result.resolve(false); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles matched results', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: []}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(true); }); it('handles delete race condition', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(undefined); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/detail.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000664000175100017510000000542515033037474032771 0ustar00mylesmyles
././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/drawer.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000664000175100017510000000052115033037474032761 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000023000000000000010210 xustar00130 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/healthmonitors.module.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/heal0000664000175100017510000001145315033037474032763 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; /** * @ngdoc overview * @ngname horizon.dashboard.project.lbaasv2.healthmonitors * * @description * Provides the services and widgets required to support and display the project healthmonitors * for the load balancers v2 panel. */ angular .module('horizon.dashboard.project.lbaasv2.healthmonitors', []) .constant('horizon.dashboard.project.lbaasv2.healthmonitors.resourceType', 'OS::Octavia::HealthMonitor') .run(run); run.$inject = [ 'horizon.framework.conf.resource-type-registry.service', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.healthmonitors.actions.create', 'horizon.dashboard.project.lbaasv2.healthmonitors.actions.edit', 'horizon.dashboard.project.lbaasv2.healthmonitors.actions.delete', 'horizon.dashboard.project.lbaasv2.healthmonitors.resourceType' ]; function run( registry, basePath, loadBalancerService, createService, editService, deleteService, resourceType ) { var healthMonitorResourceType = registry.getResourceType(resourceType); healthMonitorResourceType .setNames(gettext('Health Monitor'), gettext('Health Monitors')) .setSummaryTemplateUrl(basePath + 'healthmonitors/details/drawer.html') .setProperties(healthMonitorProperties(loadBalancerService)) .setListFunction(loadBalancerService.getHealthMonitorsPromise) .setLoadFunction(loadBalancerService.getHealthMonitorPromise) .tableColumns .append({ id: 'name', priority: 1, sortDefault: true, urlFunction: loadBalancerService.getHealthMonitorDetailsPath }) .append({ id: 'type', priority: 1 }) .append({ id: 'operating_status', priority: 1 }) .append({ id: 'provisioning_status', priority: 1 }) .append({ id: 'admin_state_up', priority: 1 }); healthMonitorResourceType.itemActions .append({ id: 'healthMonitorEdit', service: editService, template: { text: gettext('Edit Health Monitor') } }) .append({ id: 'healthMonitorDelete', service: deleteService, template: { text: gettext('Delete Health Monitor'), type: 'delete' } }); healthMonitorResourceType.globalActions .append({ id: 'healthMonitorCreate', service: createService, template: { type: 'create', text: gettext('Create Health Monitor') } }); healthMonitorResourceType.batchActions .append({ id: 'healthMonitorBatchDelete', service: deleteService, template: { text: gettext('Delete Health Monitors'), type: 'delete-selected' } }); } function healthMonitorProperties(loadBalancerService) { return { id: gettext('ID'), name: { label: gettext('Name'), filters: ['noName'] }, provisioning_status: { label: gettext('Provisioning Status'), values: loadBalancerService.provisioningStatus }, operating_status: { label: gettext('Operating Status'), values: loadBalancerService.operatingStatus }, admin_state_up: { label: gettext('Admin State Up'), filters: ['yesno'] }, type: gettext('Type'), delay: gettext('Delay'), timeout: gettext('Timeout'), max_retries: gettext('Max Retries'), max_retries_down: gettext('Max Retries Down'), http_method: { label: gettext('HTTP Method'), filters: ['noValue'] }, url_path: { label: gettext('URL Path'), filters: ['noValue'] }, expected_codes: { label: gettext('Expected Codes'), filters: ['noValue'] }, project_id: gettext('Project ID'), created_at: { label: gettext('Created At'), filters: ['noValue'] }, updated_at: { label: gettext('Updated At'), filters: ['noValue'] }, pools: gettext('Pools') }; } })(); ././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00135 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/healthmonitors.module.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/heal0000664000175100017510000000427615033037474032770 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Healthmonitors Module', function() { it('should exist', function() { expect(angular.module('horizon.dashboard.project.lbaasv2.healthmonitors')).toBeDefined(); }); }); describe('LBaaS v2 Healthmonitors Registry', function () { var registry, resourceType; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function($injector) { resourceType = $injector.get('horizon.dashboard.project.lbaasv2.healthmonitors.resourceType'); registry = $injector.get('horizon.framework.conf.resource-type-registry.service'); })); it('should define resourceType', function () { expect(resourceType).toBeDefined(); }); it('should register item actions', function () { var actions = registry.getResourceType(resourceType).itemActions; expect(actionHasId(actions, 'healthMonitorEdit')).toBe(true); expect(actionHasId(actions, 'healthMonitorDelete')).toBe(true); }); it('should register global actions', function () { var actions = registry.getResourceType(resourceType).globalActions; expect(actionHasId(actions, 'healthMonitorCreate')).toBe(true); }); it('should register batch actions', function () { var actions = registry.getResourceType(resourceType).batchActions; expect(actionHasId(actions, 'healthMonitorBatchDelete')).toBe(true); }); function actionHasId(list, value) { return list.filter(matchesId).length === 1; function matchesId(action) { return action.id === value; } } }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4671009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/0000775000175100017510000000000015033037476031137 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4551008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000775000175100017510000000000015033037476032577 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022100000000000010210 xustar00117 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/ 28 mtime=1751924542.4671009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000775000175100017510000000000015033037476032577 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024300000000000010214 xustar00141 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000000445315033037474032605 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7policies') .factory('horizon.dashboard.project.lbaasv2.l7policies.actions.create', createService); createService.$inject = [ 'horizon.dashboard.project.lbaasv2.l7policies.resourceType', 'horizon.framework.util.actions.action-result.service', '$q', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.l7policies.actions.createService * * @description * Provides the service for creating a l7policy resource. * * @param resourceType The l7policy resource type. * @param actionResultService The horizon action result service. * @param $q The angular service for promises. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns The l7policy create service. */ function createService( resourceType, actionResultService, $q, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'CreateL7PolicyWizardController', message: gettext('A new l7 policy is being created.'), handle: handle, allowed: allowed }); ////////////// function allowed() { return $q.all([ policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7policy:post']] }) ]); } function handle(response) { return actionResultService.getActionResult() .created(resourceType, response.data.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000025000000000000010212 xustar00146 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000000367415033037474032611 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Create l7policy Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'listener1' } }); } } }; } }); $provide.value('$routeParams', {}); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.l7policies.actions.create'); })); it('should not allow creating a l7policy if listenerId is not present', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); var allowed = service.allowed(); permissionShouldFail(allowed); }); it('should handle the action result properly', function() { var result = service.handle({data: {id: 1}}); expect(result.created[0].id).toBe(1); }); function permissionShouldFail(permissions) { permissions.then( function() { expect(false).toBe(true); }, function() { expect(true).toBe(true); }); } }); })(); ././@PaxHeader0000000000000000000000000000023700000000000010217 xustar00137 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000000276715033037474032613 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7policies') .controller('CreateL7PolicyWizardController', CreateL7PolicyWizardController); CreateL7PolicyWizardController.$inject = [ '$scope', '$routeParams', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; function CreateL7PolicyWizardController($scope, $routeParams, model, workflowService, gettext) { var loadbalancerId = $routeParams.loadbalancerId; var listenerId = $routeParams.listenerId; var scope = $scope; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Create L7 Policy'), 'fa fa-cloud-download', ['l7policy'] ); scope.model.initialize('l7policy', false, loadbalancerId, listenerId); } })(); ././@PaxHeader0000000000000000000000000000024400000000000010215 xustar00142 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000000360315033037474032601 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Create L7Policy Wizard Controller', function() { var ctrl; var model = { submit: function() { return 'created'; }, initialize: angular.noop }; var workflow = function() { return 'foo'; }; var scope = { launchContext: {id: '1234'} }; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow); })); beforeEach(inject(function ($controller) { spyOn(model, 'initialize'); ctrl = $controller('CreateL7PolicyWizardController', { $scope: scope }); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalled(); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe('foo'); }); it('defines scope.submit', function() { expect(scope.submit).toBeDefined(); expect(scope.submit()).toBe('created'); }); }); })(); ././@PaxHeader0000000000000000000000000000022100000000000010210 xustar00117 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/ 28 mtime=1751924542.4671009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000775000175100017510000000000015033037476032577 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024300000000000010214 xustar00141 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000001045015033037474032577 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7policies') .factory('horizon.dashboard.project.lbaasv2.l7policies.actions.delete', deleteService); deleteService.$inject = [ 'horizon.dashboard.project.lbaasv2.l7policies.resourceType', 'horizon.framework.util.actions.action-result.service', '$location', 'horizon.framework.widgets.modal.deleteModalService', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.framework.util.i18n.gettext', 'horizon.app.core.openstack-service-api.policy' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.l7policies.actions.deleteService * * @description * Brings up the delete l7policy confirmation modal dialog. * On submit, deletes selected l7policy. * On cancel, does nothing. * * @param resourceType The l7policy resource type. * @param actionResultService The horizon action result service. * @param $location The angular $location service. * @param deleteModal The horizon delete modal service. * @param api The LBaaS v2 API service. * @param gettext The horizon gettext function for translation. * @param policy The horizon policy service. * * @returns The l7policy delete service. */ function deleteService( resourceType, actionResultService, $location, deleteModal, api, gettext, policy ) { var loadbalancerId, listenerId; var service = { perform: perform, allowed: allowed, deleteResult: deleteResult // exposed just for testing }; return service; ////////////// function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7policy:delete']] }); } function perform(items, scope) { var context = { }; var l7policies = angular.isArray(items) ? items : [items]; context.labels = labelize(l7policies.length); context.deleteEntity = deleteItem; l7policies.map(function(item) { loadbalancerId = item.loadbalancerId; listenerId = item.listenerId; }); return deleteModal.open(scope, l7policies, context).then(deleteResult); } function labelize(count) { return { title: ngettext( 'Confirm Delete L7 Policy', 'Confirm Delete L7 Policies', count), message: ngettext( 'You have selected "%s". Deleted L7 Policy is not recoverable.', 'You have selected "%s". Deleted L7 Policies are not recoverable.', count), submit: ngettext( 'Delete L7 Policy', 'Delete L7 Policies', count), success: ngettext( 'Deleted L7 Policy: %s.', 'Deleted L7 Policies: %s.', count), error: ngettext( 'Unable to delete L7 Policy: %s.', 'Unable to delete L7 Policies: %s.', count) }; } function deleteResult(deleteModalResult) { // To make the result of this action generically useful, reformat the return // from the deleteModal into a standard form var actionResult = actionResultService.getActionResult(); deleteModalResult.pass.forEach(function markDeleted(item) { actionResult.deleted(resourceType, item.context.id); }); deleteModalResult.fail.forEach(function markFailed(item) { actionResult.failed(resourceType, item.context.id); }); if (actionResult.result.failed.length === 0 && actionResult.result.deleted.length > 0) { var path = 'project/load_balancer/' + loadbalancerId + '/listeners/' + listenerId; $location.path(path); } return actionResult.result; } function deleteItem(id) { return api.deleteL7Policy(id, true); } } })(); ././@PaxHeader0000000000000000000000000000025000000000000010212 xustar00146 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000000746115033037474032607 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 L7Policy Delete Service', function() { beforeEach(module('horizon.app.core')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module('horizon.framework')); var deleteModalService, service, lbaasv2API, policyAPI, $location; beforeEach(inject(function($injector) { service = $injector.get('horizon.dashboard.project.lbaasv2.l7policies.actions.delete'); lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); deleteModalService = $injector.get('horizon.framework.widgets.modal.deleteModalService'); policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy'); $location = $injector.get('$location'); })); describe('perform method', function() { beforeEach(function () { // just need for this to return something that looks like a promise but does nothing spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); }); it('should open the modal with correct label', function () { service.perform({name: 'spam'}); var labels = deleteModalService.open.calls.argsFor(0)[2].labels; expect(deleteModalService.open).toHaveBeenCalled(); angular.forEach(labels, function eachLabel(label) { expect(label.toLowerCase()).toContain('l7 policy'); }); }); it('should open the delete modal with correct entities', function () { service.perform([{name: 'one'}, {name: 'two'}]); var entities = deleteModalService.open.calls.argsFor(0)[1]; expect(deleteModalService.open).toHaveBeenCalled(); expect(entities.length).toEqual(2); }); it('should pass in a function that deletes a l7 policy', function () { spyOn(lbaasv2API, 'deleteL7Policy').and.callFake(angular.noop); service.perform({id: 1, name: 'one'}); var contextArg = deleteModalService.open.calls.argsFor(0)[2]; var deleteFunction = contextArg.deleteEntity; deleteFunction(1); expect(lbaasv2API.deleteL7Policy).toHaveBeenCalledWith(1, true); }); }); it('should handle the action result properly', function() { spyOn($location, 'path'); spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); spyOn(lbaasv2API, 'deleteL7Policy').and.callFake(angular.noop); service.perform({loadbalancerId: 1, listenerId: 2, id: 1, name: 'one'}); var result = service.deleteResult({ fail: [], pass: [{ context: { id: 1 } }] }); var path = 'project/load_balancer/1/listeners/2'; expect($location.path).toHaveBeenCalledWith(path); expect(result.deleted[0].id).toBe(1); result = service.deleteResult({ pass: [], fail: [{ context: { id: 1 } }] }); expect(result.failed[0].id).toBe(1); }); describe('allow method', function() { it('should use default policy if batch action', function () { spyOn(policyAPI, 'ifAllowed'); service.allowed(); expect(policyAPI.ifAllowed).toHaveBeenCalled(); }); }); // end of allowed }); // end of delete })(); ././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00115 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/ 28 mtime=1751924542.4681008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000775000175100017510000000000015033037476032577 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023700000000000010217 xustar00137 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000000431715033037474032604 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7policies') .factory('horizon.dashboard.project.lbaasv2.l7policies.actions.edit', editService); editService.$inject = [ 'horizon.dashboard.project.lbaasv2.l7policies.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.l7policies.actions.editService * * @description * Provides the service for editing a l7policy resource. * * @param resourceType The l7policy resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns The l7policy edit service. */ function editService( resourceType, actionResultService, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'EditL7PolicyWizardController', message: gettext('The l7policy has been updated.'), handle: handle, allowed: allowed }); function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7policy:put']] }); } function handle(response) { return actionResultService.getActionResult() .updated(resourceType, response.config.data.l7policy.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000024400000000000010215 xustar00142 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000000331615033037474032602 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Edit L7Policy Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'l7policy1' } }); } } }; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.l7policies.actions.edit'); })); it('should check policy to allow editing a l7policy', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); expect(service.allowed()).toBe(true); expect(policy.ifAllowed).toHaveBeenCalled(); }); it('should handle the action result properly', function() { var result = service.handle({config: {data: {l7policy: {id: 1}}}}); expect(result.updated[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00135 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000000400015033037474032571 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .controller('EditL7PolicyWizardController', EditL7PolicyWizardController); EditL7PolicyWizardController.$inject = [ '$scope', '$routeParams', '$q', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name EditL7PolicyWizardController * * @description * Controller for the LBaaS v2 edit l7policy wizard. * * @param $scope The angular scope object. * @param $routeParams The angular $routeParams service. * @param $q The angular service for promises. * @param model The LBaaS V2 workflow model service. * @param workflowService The LBaaS V2 workflow service. * @param gettext The horizon gettext function for translation. * @returns undefined */ function EditL7PolicyWizardController($scope, $routeParams, $q, model, workflowService, gettext) { var scope = $scope; var loadbalancerId = $routeParams.loadbalancerId; var listenerId = $routeParams.listenerId; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Update L7 Policy'), 'fa fa-pencil', ['l7policy']); scope.model.initialize('l7policy', scope.launchContext.id, loadbalancerId, listenerId); } })(); ././@PaxHeader0000000000000000000000000000024200000000000010213 xustar00140 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000664000175100017510000000505015033037474032577 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Edit L7Policy Wizard Controller', function() { var ctrl, workflowSpy, $q, scope; var model = { submit: function() { return 'updated'; }, initialize: function() { var defer = $q.defer(); defer.resolve(); return defer.promise; } }; var workflow = { steps: [{id: 'l7policy'}], append: angular.noop }; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { workflowSpy = jasmine.createSpy('workflow').and.returnValue(workflow); $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflowSpy); })); beforeEach(inject(function ($controller, $injector) { $q = $injector.get('$q'); scope = $injector.get('$rootScope').$new(); scope.launchContext = { id: 'l7policyId' }; spyOn(model, 'initialize').and.callThrough(); ctrl = $controller('EditL7PolicyWizardController', { $scope: scope, $routeParams: {loadbalancerId: 'loadbalancerId', listenerId: 'listenerId'}}); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalledWith( 'l7policy', 'l7policyId', 'loadbalancerId', 'listenerId'); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe(workflow); }); it('initializes workflow with correct properties', function() { expect(workflowSpy).toHaveBeenCalledWith('Update L7 Policy', 'fa fa-pencil', ['l7policy']); }); it('defines scope.submit', function() { expect(scope.submit).toBe(model.submit); expect(scope.submit()).toBe('updated'); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4681008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000775000175100017510000000000015033037476032564 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023000000000000010210 xustar00130 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000664000175100017510000001154415033037474032571 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7policies') .controller('L7PolicyDetailController', L7PolicyDetailController); L7PolicyDetailController.$inject = [ '$timeout', 'horizon.dashboard.project.lbaasv2.events', '$scope', 'loadbalancer', 'listener', 'l7policy', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.l7policies.resourceType', 'horizon.framework.conf.resource-type-registry.service', 'horizon.framework.widgets.modal-wait-spinner.service', '$q' ]; /** * @ngdoc controller * @name L7PolicyDetailController * * @description * Controller for the LBaaS v2 l7policy detail page. * * @param $timeout The angular timeout object. * @param events The LBaaS v2 events object. * @param $scope The angular scope object. * @param loadbalancer The loadbalancer object. * @param listener The listener object. * @param l7policy The l7policy object. * @param loadBalancersService The LBaaS v2 load balancers service. * @param resourceType The load balancer resource type. * @param typeRegistry The horizon type registry service. * @param spinnerService The horizon modal wait spinner service. * @param $q The angular service for promises. * * @returns undefined */ function L7PolicyDetailController( $timeout, events, $scope, loadbalancer, listener, l7policy, loadBalancersService, resourceType, typeRegistry, spinnerService, $q ) { var ctrl = this; ctrl.operatingStatus = loadBalancersService.operatingStatus; ctrl.provisioningStatus = loadBalancersService.provisioningStatus; ctrl.l7policyAction = loadBalancersService.l7policyAction; ctrl.loadbalancer = loadbalancer; ctrl.listener = listener; ctrl.l7policy = l7policy; ctrl.listFunctionExtraParams = { loadbalancerId: ctrl.loadbalancer.id, listenerId: ctrl.listener.id, l7policyId: ctrl.l7policy.id }; ctrl.resourceType = typeRegistry.getResourceType(resourceType); ctrl.context = {}; ctrl.context.identifier = l7policy.id; ctrl.resultHandler = actionResultHandler; $scope.$watch( function() { return ctrl.l7policy; }, function() { $timeout.cancel($scope.loadTimeout); $scope.loadTimeout = $timeout(function() { ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); }, loadBalancersService.backoff.duration()); } ); $scope.$on( events.ACTION_DONE, function() { loadBalancersService.backoff.reset(); ctrl.l7policy = angular.copy(ctrl.l7policy); } ); $scope.$on( '$destroy', function() { $timeout.cancel($scope.loadTimeout); } ); function actionResultHandler(returnValue) { return $q.when(returnValue, actionSuccessHandler); } function loadData(response) { spinnerService.hideModalSpinner(); ctrl.showDetails = true; ctrl.resourceType.initActions(); ctrl.l7policy = response.data; ctrl.l7policy.loadbalancerId = ctrl.loadbalancer.id; ctrl.l7policy.listenerId = ctrl.listener.id; ctrl.listFunctionExtraParams = { loadbalancerId: ctrl.loadbalancer.id, listenerId: ctrl.listener.id, l7policyId: ctrl.l7policy.id }; } function actionSuccessHandler(result) { // The action has completed (for whatever "complete" means to that // action. Notice the view doesn't really need to know the semantics of the // particular action because the actions return data in a standard form. // That return includes the id and type of each created, updated, deleted // and failed item. // Currently just refreshes the display each time. if (result) { if (result.failed.length === 0 && result.deleted.length > 0) { // handle a race condition where the resource is already deleted return; } spinnerService.showModalSpinner(gettext('Please Wait')); ctrl.showDetails = false; ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); } } } })(); ././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00135 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000664000175100017510000001113215033037474032562 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 L7Policy Detail Controller', function() { var deferred, service, ctrl, scope, $timeout, $q, actionResultService; /////////////////////// beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModal', {}); })); beforeEach(inject(function($controller, $rootScope, _$q_, _$timeout_) { $q = _$q_; deferred = $q.defer(); service = { getResourceType: function() { return { load: function() { return deferred.promise; }, parsePath: function() { return 'my-context'; }, itemName: function() { return 'A name'; }, initActions: angular.noop }; }, getDefaultDetailsTemplateUrl: angular.noop }; actionResultService = { getIdsOfType: function() { return []; } }; $timeout = _$timeout_; scope = $rootScope.$new(); ctrl = $controller('L7PolicyDetailController', { $scope: scope, loadbalancer: { id: '123' }, listener: { id: '123' }, l7policy: { id: '123', provisioning_status: 'ACTIVE' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); })); it('should create a controller', function() { expect(ctrl).toBeDefined(); expect(ctrl.loadbalancer).toBeDefined(); expect(ctrl.listener).toBeDefined(); expect(ctrl.l7policy).toBeDefined(); }); describe('data watchers', function() { var events, loadBalancersService; beforeEach(inject(function($injector) { events = $injector.get('horizon.dashboard.project.lbaasv2.events'); loadBalancersService = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.service' ); })); it('should refresh on provisioning status change', function() { var loadFunctionDeferred = $q.defer(); spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise); ctrl.l7policy = { id: '123', provisioning_status: 'PENDING_UPDATE' }; scope.$apply(); $timeout.flush(); expect(ctrl.resourceType.load).toHaveBeenCalled(); spyOn(loadBalancersService.backoff, 'reset').and.callThrough(); scope.$broadcast(events.ACTION_DONE); expect(loadBalancersService.backoff.reset).toHaveBeenCalled(); }); }); describe('resultHandler', function() { it('handles empty results', function() { var result = $q.defer(); result.resolve({failed: [], deleted: []}); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles falsy results', function() { var result = $q.defer(); result.resolve(false); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles matched results', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: []}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(true); }); it('handles delete race condition', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(undefined); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00121 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000664000175100017510000000516215033037474032570 0ustar00mylesmyles
././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00121 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/drawer.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000664000175100017510000000046215033037474032566 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000022000000000000010207 xustar00122 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7polici0000664000175100017510000001132715033037474032606 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; /** * @ngdoc overview * @ngname horizon.dashboard.project.lbaasv2.l7policies * * @description * Provides the services and widgets required to support and display the project l7 policies * for the load balancers v2 panel. */ angular .module('horizon.dashboard.project.lbaasv2.l7policies', []) .constant('horizon.dashboard.project.lbaasv2.l7policies.resourceType', 'OS::Octavia::L7Policy') .run(run); run.$inject = [ 'horizon.framework.conf.resource-type-registry.service', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.l7policies.actions.create', 'horizon.dashboard.project.lbaasv2.l7policies.actions.edit', 'horizon.dashboard.project.lbaasv2.l7policies.actions.delete', 'horizon.dashboard.project.lbaasv2.l7policies.resourceType' ]; function run( registry, basePath, loadBalancerService, createService, editService, deleteService, resourceType ) { var l7policyResourceType = registry.getResourceType(resourceType); l7policyResourceType .setNames(gettext('L7 Policy'), gettext('L7 Policies')) .setSummaryTemplateUrl(basePath + 'l7policies/details/drawer.html') .setProperties(l7policyProperties(loadBalancerService)) .setListFunction(loadBalancerService.getL7PoliciesPromise) .setLoadFunction(loadBalancerService.getL7PolicyPromise) .tableColumns .append({ id: 'name', priority: 1, urlFunction: loadBalancerService.getL7PolicyDetailsPath }) .append({ id: 'position', sortDefault: true, priority: 1 }) .append({ id: 'action', priority: 1 }) .append({ id: 'operating_status', priority: 1 }) .append({ id: 'provisioning_status', priority: 1 }) .append({ id: 'admin_state_up', priority: 1 }); l7policyResourceType.itemActions .append({ id: 'l7policyEdit', service: editService, template: { text: gettext('Edit L7 Policy') } }) .append({ id: 'l7policyDelete', service: deleteService, template: { text: gettext('Delete L7 Policy'), type: 'delete' } }); l7policyResourceType.globalActions .append({ id: 'l7policyCreate', service: createService, template: { type: 'create', text: gettext('Create L7 Policy') } }); l7policyResourceType.batchActions .append({ id: 'l7policyBatchDelete', service: deleteService, template: { text: gettext('Delete L7 Policies'), type: 'delete-selected' } }); } function l7policyProperties(loadBalancerService) { return { id: gettext('ID'), name: { label: gettext('Name'), filters: ['noName'] }, description: { label: gettext('Description'), filters: ['noName'] }, provisioning_status: { label: gettext('Provisioning Status'), values: loadBalancerService.provisioningStatus }, operating_status: { label: gettext('Operating Status'), values: loadBalancerService.operatingStatus }, admin_state_up: { label: gettext('Admin State Up'), filters: ['yesno'] }, action: { label: gettext('Action'), values: loadBalancerService.l7policyAction }, redirect_url: { label: gettext('Redirect URL'), filters: ['noValue'] }, redirect_pool_id: { label: gettext('Redirect Pool ID'), filters: ['noValue'] }, project_id: gettext('Project ID'), created_at: { label: gettext('Created At'), filters: ['noValue'] }, updated_at: { label: gettext('Updated At'), filters: ['noValue'] }, position: gettext('Position'), listener_id: gettext('Listener ID'), rules: gettext('Rules') }; } })(); ././@PaxHeader0000000000000000000000000000022500000000000010214 xustar00127 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7polici0000664000175100017510000000417615033037474032612 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 L7Policies Module', function() { it('should exist', function() { expect(angular.module('horizon.dashboard.project.lbaasv2.l7policies')).toBeDefined(); }); }); describe('LBaaS v2 L7Policies Registry', function () { var registry, resourceType; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function($injector) { resourceType = $injector.get('horizon.dashboard.project.lbaasv2.l7policies.resourceType'); registry = $injector.get('horizon.framework.conf.resource-type-registry.service'); })); it('should define resourceType', function () { expect(resourceType).toBeDefined(); }); it('should register item actions', function () { var actions = registry.getResourceType(resourceType).itemActions; expect(actionHasId(actions, 'l7policyEdit')).toBe(true); expect(actionHasId(actions, 'l7policyDelete')).toBe(true); }); it('should register global actions', function () { var actions = registry.getResourceType(resourceType).globalActions; expect(actionHasId(actions, 'l7policyCreate')).toBe(true); }); it('should register batch actions', function () { var actions = registry.getResourceType(resourceType).batchActions; expect(actionHasId(actions, 'l7policyBatchDelete')).toBe(true); }); function actionHasId(list, value) { return list.filter(matchesId).length === 1; function matchesId(action) { return action.id === value; } } }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4681008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/0000775000175100017510000000000015033037476030462 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4551008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/0000775000175100017510000000000015033037476032122 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00114 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/ 28 mtime=1751924542.4681008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000775000175100017510000000000015033037476032614 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024000000000000010211 xustar00138 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000664000175100017510000000442515033037474032621 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7rules') .factory('horizon.dashboard.project.lbaasv2.l7rules.actions.create', createService); createService.$inject = [ 'horizon.dashboard.project.lbaasv2.l7rules.resourceType', 'horizon.framework.util.actions.action-result.service', '$q', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.l7rules.actions.createService * * @description * Provides the service for creating a l7rule resource. * * @param resourceType The l7rule resource type. * @param actionResultService The horizon action result service. * @param $q The angular service for promises. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns The l7rule create service. */ function createService( resourceType, actionResultService, $q, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'CreateL7RuleWizardController', message: gettext('A new l7 policy is being created.'), handle: handle, allowed: allowed }); ////////////// function allowed() { return $q.all([ policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7rule:post']] }) ]); } function handle(response) { return actionResultService.getActionResult() .created(resourceType, response.data.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000024500000000000010216 xustar00143 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000664000175100017510000000366515033037474032626 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Create l7rule Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'listener1' } }); } } }; } }); $provide.value('$routeParams', {}); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.l7rules.actions.create'); })); it('should not allow creating a l7rule if listenerId is not present', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); var allowed = service.allowed(); permissionShouldFail(allowed); }); it('should handle the action result properly', function() { var result = service.handle({data: {id: 1}}); expect(result.created[0].id).toBe(1); }); function permissionShouldFail(permissions) { permissions.then( function() { expect(false).toBe(true); }, function() { expect(true).toBe(true); }); } }); })(); ././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00134 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000664000175100017510000000274615033037474032625 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7rules') .controller('CreateL7RuleWizardController', CreateL7RuleWizardController); CreateL7RuleWizardController.$inject = [ '$scope', '$routeParams', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; function CreateL7RuleWizardController($scope, $routeParams, model, workflowService, gettext) { var loadbalancerId = $routeParams.loadbalancerId; var l7policyId = $routeParams.l7policyId; var scope = $scope; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Create L7 Rule'), 'fa fa-cloud-download', ['l7rule'] ); scope.model.initialize('l7rule', false, loadbalancerId, l7policyId); } })(); ././@PaxHeader0000000000000000000000000000024100000000000010212 xustar00139 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000664000175100017510000000357715033037474032630 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Create L7Rule Wizard Controller', function() { var ctrl; var model = { submit: function() { return 'created'; }, initialize: angular.noop }; var workflow = function() { return 'foo'; }; var scope = { launchContext: {id: '1234'} }; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow); })); beforeEach(inject(function ($controller) { spyOn(model, 'initialize'); ctrl = $controller('CreateL7RuleWizardController', { $scope: scope }); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalled(); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe('foo'); }); it('defines scope.submit', function() { expect(scope.submit).toBeDefined(); expect(scope.submit()).toBe('created'); }); }); })(); ././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00114 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/ 28 mtime=1751924542.4681008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/del0000775000175100017510000000000015033037476032607 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024000000000000010211 xustar00138 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/del0000664000175100017510000001051015033037474032604 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7rules') .factory('horizon.dashboard.project.lbaasv2.l7rules.actions.delete', deleteService); deleteService.$inject = [ 'horizon.dashboard.project.lbaasv2.l7rules.resourceType', 'horizon.framework.util.actions.action-result.service', '$location', 'horizon.framework.widgets.modal.deleteModalService', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.framework.util.i18n.gettext', 'horizon.app.core.openstack-service-api.policy' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.l7rules.actions.deleteService * * @description * Brings up the delete l7rule confirmation modal dialog. * On submit, deletes selected l7rule. * On cancel, does nothing. * * @param resourceType The l7rule resource type. * @param actionResultService The horizon action result service. * @param $location The angular $location service. * @param deleteModal The horizon delete modal service. * @param api The LBaaS v2 API service. * @param gettext The horizon gettext function for translation. * @param policy The horizon policy service. * * @returns The l7rule delete service. */ function deleteService( resourceType, actionResultService, $location, deleteModal, api, gettext, policy ) { var loadbalancerId, listenerId, l7policyId; var service = { perform: perform, allowed: allowed, deleteResult: deleteResult // exposed just for testing }; return service; ////////////// function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7rule:delete']] }); } function perform(items, scope) { var context = { }; var l7rules = angular.isArray(items) ? items : [items]; context.labels = labelize(l7rules.length); context.deleteEntity = deleteItem; l7rules.map(function(item) { loadbalancerId = item.loadbalancerId; listenerId = item.listenerId; l7policyId = item.l7policyId; }); return deleteModal.open(scope, l7rules, context).then(deleteResult); } function labelize(count) { return { title: ngettext( 'Confirm Delete L7 Rule', 'Confirm Delete L7 Rules', count), message: ngettext( 'You have selected "%s". Deleted L7 Rule is not recoverable.', 'You have selected "%s". Deleted L7 Rules are not recoverable.', count), submit: ngettext( 'Delete L7 Rule', 'Delete L7 Rules', count), success: ngettext( 'Deleted L7 Rule: %s.', 'Deleted L7 Rules: %s.', count), error: ngettext( 'Unable to delete L7 Rule: %s.', 'Unable to delete L7 Rules: %s.', count) }; } function deleteResult(deleteModalResult) { // To make the result of this action generically useful, reformat the return // from the deleteModal into a standard form var actionResult = actionResultService.getActionResult(); deleteModalResult.pass.forEach(function markDeleted(item) { actionResult.deleted(resourceType, item.context.id); }); deleteModalResult.fail.forEach(function markFailed(item) { actionResult.failed(resourceType, item.context.id); }); if (actionResult.result.failed.length === 0 && actionResult.result.deleted.length > 0) { var path = 'project/load_balancer/' + loadbalancerId + '/listeners/' + listenerId + '/l7policies/' + l7policyId; $location.path(path); } return actionResult.result; } function deleteItem(id) { return api.deleteL7Rule(l7policyId, id, true); } } })(); ././@PaxHeader0000000000000000000000000000024500000000000010216 xustar00143 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/del0000664000175100017510000000752015033037474032613 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 L7Rule Delete Service', function() { beforeEach(module('horizon.app.core')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module('horizon.framework')); var deleteModalService, service, lbaasv2API, policyAPI, $location; beforeEach(inject(function($injector) { service = $injector.get('horizon.dashboard.project.lbaasv2.l7rules.actions.delete'); lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); deleteModalService = $injector.get('horizon.framework.widgets.modal.deleteModalService'); policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy'); $location = $injector.get('$location'); })); describe('perform method', function() { beforeEach(function () { // just need for this to return something that looks like a promise but does nothing spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); }); it('should open the modal with correct label', function () { service.perform({name: 'spam'}); var labels = deleteModalService.open.calls.argsFor(0)[2].labels; expect(deleteModalService.open).toHaveBeenCalled(); angular.forEach(labels, function eachLabel(label) { expect(label.toLowerCase()).toContain('l7 rule'); }); }); it('should open the delete modal with correct entities', function () { service.perform([{name: 'one'}, {name: 'two'}]); var entities = deleteModalService.open.calls.argsFor(0)[1]; expect(deleteModalService.open).toHaveBeenCalled(); expect(entities.length).toEqual(2); }); it('should pass in a function that deletes a l7 rule', function () { spyOn(lbaasv2API, 'deleteL7Rule').and.callFake(angular.noop); service.perform({l7policyId: 2, id: 1, name: 'one'}); var contextArg = deleteModalService.open.calls.argsFor(0)[2]; var deleteFunction = contextArg.deleteEntity; deleteFunction(1); expect(lbaasv2API.deleteL7Rule).toHaveBeenCalledWith(2, 1, true); }); }); it('should handle the action result properly', function() { spyOn($location, 'path'); spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); spyOn(lbaasv2API, 'deleteL7Rule').and.callFake(angular.noop); service.perform({loadbalancerId: 1, listenerId: 2, l7policyId: 3, id: 1, name: 'one'}); var result = service.deleteResult({ fail: [], pass: [{ context: { id: 1 } }] }); var path = 'project/load_balancer/1/listeners/2/l7policies/3'; expect($location.path).toHaveBeenCalledWith(path); expect(result.deleted[0].id).toBe(1); result = service.deleteResult({ pass: [], fail: [{ context: { id: 1 } }] }); expect(result.failed[0].id).toBe(1); }); describe('allow method', function() { it('should use default policy if batch action', function () { spyOn(policyAPI, 'ifAllowed'); service.allowed(); expect(policyAPI.ifAllowed).toHaveBeenCalled(); }); }); // end of allowed }); // end of delete })(); ././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00112 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/ 28 mtime=1751924542.4681008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000775000175100017510000000000015033037476032604 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00134 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000664000175100017510000000426515033037474032613 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7rules') .factory('horizon.dashboard.project.lbaasv2.l7rules.actions.edit', editService); editService.$inject = [ 'horizon.dashboard.project.lbaasv2.l7rules.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.l7rules.actions.editService * * @description * Provides the service for editing a l7rule resource. * * @param resourceType The l7rule resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns The l7rule edit service. */ function editService( resourceType, actionResultService, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'EditL7RuleWizardController', message: gettext('The l7rule has been updated.'), handle: handle, allowed: allowed }); function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:l7rule:put']] }); } function handle(response) { return actionResultService.getActionResult() .updated(resourceType, response.config.data.l7rule.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000024100000000000010212 xustar00139 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000664000175100017510000000330315033037474032603 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Edit L7Rule Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'l7rule1' } }); } } }; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.l7rules.actions.edit'); })); it('should check policy to allow editing a l7rule', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); expect(service.allowed()).toBe(true); expect(policy.ifAllowed).toHaveBeenCalled(); }); it('should handle the action result properly', function() { var result = service.handle({config: {data: {l7rule: {id: 1}}}}); expect(result.updated[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000023200000000000010212 xustar00132 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000664000175100017510000000375615033037474032617 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .controller('EditL7RuleWizardController', EditL7RuleWizardController); EditL7RuleWizardController.$inject = [ '$scope', '$routeParams', '$q', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name EditL7RuleWizardController * * @description * Controller for the LBaaS v2 edit l7rule wizard. * * @param $scope The angular scope object. * @param $routeParams The angular $routeParams service. * @param $q The angular service for promises. * @param model The LBaaS V2 workflow model service. * @param workflowService The LBaaS V2 workflow service. * @param gettext The horizon gettext function for translation. * @returns undefined */ function EditL7RuleWizardController($scope, $routeParams, $q, model, workflowService, gettext) { var scope = $scope; var loadbalancerId = $routeParams.loadbalancerId; var l7policyId = $routeParams.l7policyId; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Update L7 Rule'), 'fa fa-pencil', ['l7rule']); scope.model.initialize('l7rule', scope.launchContext.id, loadbalancerId, l7policyId); } })(); ././@PaxHeader0000000000000000000000000000023700000000000010217 xustar00137 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000664000175100017510000000503015033037474032602 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Edit L7Rule Wizard Controller', function() { var ctrl, workflowSpy, $q, scope; var model = { submit: function() { return 'updated'; }, initialize: function() { var defer = $q.defer(); defer.resolve(); return defer.promise; } }; var workflow = { steps: [{id: 'l7rule'}], append: angular.noop }; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { workflowSpy = jasmine.createSpy('workflow').and.returnValue(workflow); $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflowSpy); })); beforeEach(inject(function ($controller, $injector) { $q = $injector.get('$q'); scope = $injector.get('$rootScope').$new(); scope.launchContext = { id: 'l7ruleId' }; spyOn(model, 'initialize').and.callThrough(); ctrl = $controller('EditL7RuleWizardController', { $scope: scope, $routeParams: {loadbalancerId: 'loadbalancerId', l7policyId: 'l7policyId'}}); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalledWith( 'l7rule', 'l7ruleId', 'loadbalancerId', 'l7policyId'); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe(workflow); }); it('initializes workflow with correct properties', function() { expect(workflowSpy).toHaveBeenCalledWith('Update L7 Rule', 'fa fa-pencil', ['l7rule']); }); it('defines scope.submit', function() { expect(scope.submit).toBe(model.submit); expect(scope.submit()).toBe('updated'); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4681008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/0000775000175100017510000000000015033037476032107 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022500000000000010214 xustar00127 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/det0000664000175100017510000001174715033037474032616 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.l7rules') .controller('L7RuleDetailController', L7RuleDetailController); L7RuleDetailController.$inject = [ '$timeout', 'horizon.dashboard.project.lbaasv2.events', '$scope', 'loadbalancer', 'listener', 'l7policy', 'l7rule', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.l7rules.resourceType', 'horizon.framework.conf.resource-type-registry.service', 'horizon.framework.widgets.modal-wait-spinner.service', '$q' ]; /** * @ngdoc controller * @name L7RuleDetailController * * @description * Controller for the LBaaS v2 l7rule detail page. * * @param $timeout The angular timeout object. * @param events The LBaaS v2 events object. * @param $scope The angular scope object. * @param loadbalancer The loadbalancer object. * @param listener The listener object. * @param l7policy The l7policy object. * @param l7rule The l7rule object. * @param loadBalancersService The LBaaS v2 load balancers service. * @param resourceType The load balancer resource type. * @param typeRegistry The horizon type registry service. * @param spinnerService The horizon modal wait spinner service. * @param $q The angular service for promises. * * @returns undefined */ function L7RuleDetailController( $timeout, events, $scope, loadbalancer, listener, l7policy, l7rule, loadBalancersService, resourceType, typeRegistry, spinnerService, $q ) { var ctrl = this; ctrl.operatingStatus = loadBalancersService.operatingStatus; ctrl.provisioningStatus = loadBalancersService.provisioningStatus; ctrl.l7ruleType = loadBalancersService.l7ruleType; ctrl.l7ruleCompareType = loadBalancersService.l7ruleCompareType; ctrl.loadbalancer = loadbalancer; ctrl.listener = listener; ctrl.l7policy = l7policy; ctrl.l7rule = l7rule; ctrl.listFunctionExtraParams = { loadbalancerId: ctrl.loadbalancer.id, listenerId: ctrl.listener.id, l7policyId: ctrl.l7policy.id, l7ruleId: ctrl.l7rule.id }; ctrl.resourceType = typeRegistry.getResourceType(resourceType); ctrl.context = {}; ctrl.context.l7policyId = l7policy.id; ctrl.context.l7ruleId = l7rule.id; ctrl.resultHandler = actionResultHandler; $scope.$watch( function() { return ctrl.l7rule; }, function() { $timeout.cancel($scope.loadTimeout); $scope.loadTimeout = $timeout(function() { ctrl.context.loadPromise = ctrl.resourceType.load( ctrl.context.l7policyId, ctrl.context.l7ruleId ); ctrl.context.loadPromise.then(loadData); }, loadBalancersService.backoff.duration()); } ); $scope.$on( events.ACTION_DONE, function() { loadBalancersService.backoff.reset(); } ); $scope.$on( '$destroy', function() { $timeout.cancel($scope.loadTimeout); } ); function actionResultHandler(returnValue) { return $q.when(returnValue, actionSuccessHandler); } function loadData(response) { spinnerService.hideModalSpinner(); ctrl.showDetails = true; ctrl.resourceType.initActions(); ctrl.l7rule = response.data; ctrl.l7rule.loadbalancerId = ctrl.loadbalancer.id; ctrl.l7rule.listenerId = ctrl.listener.id; ctrl.l7rule.l7policyId = ctrl.l7policy.id; } function actionSuccessHandler(result) { // The action has completed (for whatever "complete" means to that // action. Notice the view doesn't really need to know the semantics of the // particular action because the actions return data in a standard form. // That return includes the id and type of each created, updated, deleted // and failed item. // Currently just refreshes the display each time. if (result) { if (result.failed.length === 0 && result.deleted.length > 0) { // handle a race condition where the resource is already deleted return; } spinnerService.showModalSpinner(gettext('Please Wait')); ctrl.showDetails = false; ctrl.context.loadPromise = ctrl.resourceType.load( ctrl.context.l7policyId, ctrl.context.l7ruleId ); ctrl.context.loadPromise.then(loadData); } } } })(); ././@PaxHeader0000000000000000000000000000023200000000000010212 xustar00132 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/det0000664000175100017510000001123415033037474032605 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 L7Rule Detail Controller', function() { var deferred, service, ctrl, scope, $timeout, $q, actionResultService; /////////////////////// beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModal', {}); })); beforeEach(inject(function($controller, $rootScope, _$q_, _$timeout_) { $q = _$q_; deferred = $q.defer(); service = { getResourceType: function() { return { load: function() { return deferred.promise; }, parsePath: function() { return 'my-context'; }, itemName: function() { return 'A name'; }, initActions: angular.noop }; }, getDefaultDetailsTemplateUrl: angular.noop }; actionResultService = { getIdsOfType: function() { return []; } }; $timeout = _$timeout_; scope = $rootScope.$new(); ctrl = $controller('L7RuleDetailController', { $scope: scope, loadbalancer: { id: '123' }, listener: { id: '123' }, l7policy: { id: '123' }, l7rule: { id: '123', provisioning_status: 'ACTIVE' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); })); it('should create a controller', function() { expect(ctrl).toBeDefined(); expect(ctrl.loadbalancer).toBeDefined(); expect(ctrl.listener).toBeDefined(); expect(ctrl.l7policy).toBeDefined(); expect(ctrl.l7rule).toBeDefined(); }); describe('data watchers', function() { var events, loadBalancersService; beforeEach(inject(function($injector) { events = $injector.get('horizon.dashboard.project.lbaasv2.events'); loadBalancersService = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.service' ); })); it('should refresh on provisioning status change', function() { var loadFunctionDeferred = $q.defer(); spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise); ctrl.l7rule = { id: '123', provisioning_status: 'PENDING_UPDATE' }; scope.$apply(); $timeout.flush(); expect(ctrl.resourceType.load).toHaveBeenCalled(); spyOn(loadBalancersService.backoff, 'reset').and.callThrough(); scope.$broadcast(events.ACTION_DONE); expect(loadBalancersService.backoff.reset).toHaveBeenCalled(); }); }); describe('resultHandler', function() { it('handles empty results', function() { var result = $q.defer(); result.resolve({failed: [], deleted: []}); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles falsy results', function() { var result = $q.defer(); result.resolve(false); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles matched results', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: []}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(true); }); it('handles delete race condition', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(undefined); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00118 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/det0000664000175100017510000000460115033037474032605 0ustar00mylesmyles
././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.mod0000664000175100017510000001120415033037474032554 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; /** * @ngdoc overview * @ngname horizon.dashboard.project.lbaasv2.l7rules * * @description * Provides the services and widgets required to support and display the project l7 rules * for the load balancers v2 panel. */ angular .module('horizon.dashboard.project.lbaasv2.l7rules', []) .constant('horizon.dashboard.project.lbaasv2.l7rules.resourceType', 'OS::Octavia::L7Rule') .run(run); run.$inject = [ 'horizon.framework.conf.resource-type-registry.service', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.l7rules.actions.create', 'horizon.dashboard.project.lbaasv2.l7rules.actions.edit', 'horizon.dashboard.project.lbaasv2.l7rules.actions.delete', 'horizon.dashboard.project.lbaasv2.l7rules.resourceType' ]; function run( registry, basePath, loadBalancerService, createService, editService, deleteService, resourceType ) { var l7ruleResourceType = registry.getResourceType(resourceType); l7ruleResourceType .setNames(gettext('L7 Rule'), gettext('L7 Rules')) .setSummaryTemplateUrl(basePath + 'l7rules/details/drawer.html') .setProperties(l7ruleProperties(loadBalancerService)) .setListFunction(loadBalancerService.getL7RulesPromise) .setLoadFunction(loadBalancerService.getL7RulePromise) .tableColumns .append({ id: 'type', priority: 1, urlFunction: loadBalancerService.getL7RuleDetailsPath }) .append({ id: 'compare_type', priority: 1 }) .append({ id: 'key', priority: 1 }) .append({ id: 'rule_value', priority: 1 }) .append({ id: 'invert', priority: 1 }) .append({ id: 'operating_status', priority: 1 }) .append({ id: 'provisioning_status', priority: 1 }) .append({ id: 'admin_state_up', priority: 1 }); l7ruleResourceType.itemActions .append({ id: 'l7ruleEdit', service: editService, template: { text: gettext('Edit L7 Rule') } }) .append({ id: 'l7ruleDelete', service: deleteService, template: { text: gettext('Delete L7 Rule'), type: 'delete' } }); l7ruleResourceType.globalActions .append({ id: 'l7ruleCreate', service: createService, template: { type: 'create', text: gettext('Create L7 Rule') } }); l7ruleResourceType.batchActions .append({ id: 'l7ruleBatchDelete', service: deleteService, template: { text: gettext('Delete L7 Rules'), type: 'delete-selected' } }); } function l7ruleProperties(loadBalancerService) { return { id: gettext('ID'), type: { label: gettext('Type'), values: loadBalancerService.l7ruleType }, compare_type: { label: gettext('Compare Type'), values: loadBalancerService.l7ruleCompareType }, provisioning_status: { label: gettext('Provisioning Status'), values: loadBalancerService.provisioningStatus }, operating_status: { label: gettext('Operating Status'), values: loadBalancerService.operatingStatus }, admin_state_up: { label: gettext('Admin State Up'), filters: ['yesno'] }, key: { label: gettext('Key'), filters: ['noValue'] }, rule_value: { label: gettext('Value'), filters: ['noValue'] }, invert: { label: gettext('Invert'), filters: ['yesno'] }, project_id: gettext('Project ID'), created_at: { label: gettext('Created At'), filters: ['noValue'] }, updated_at: { label: gettext('Updated At'), filters: ['noValue'] } }; } })(); ././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00121 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.mod0000664000175100017510000000415215033037474032560 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 L7Rules Module', function() { it('should exist', function() { expect(angular.module('horizon.dashboard.project.lbaasv2.l7rules')).toBeDefined(); }); }); describe('LBaaS v2 L7Rules Registry', function () { var registry, resourceType; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function($injector) { resourceType = $injector.get('horizon.dashboard.project.lbaasv2.l7rules.resourceType'); registry = $injector.get('horizon.framework.conf.resource-type-registry.service'); })); it('should define resourceType', function () { expect(resourceType).toBeDefined(); }); it('should register item actions', function () { var actions = registry.getResourceType(resourceType).itemActions; expect(actionHasId(actions, 'l7ruleEdit')).toBe(true); expect(actionHasId(actions, 'l7ruleDelete')).toBe(true); }); it('should register global actions', function () { var actions = registry.getResourceType(resourceType).globalActions; expect(actionHasId(actions, 'l7ruleCreate')).toBe(true); }); it('should register batch actions', function () { var actions = registry.getResourceType(resourceType).batchActions; expect(actionHasId(actions, 'l7ruleBatchDelete')).toBe(true); }); function actionHasId(list, value) { return list.filter(matchesId).length === 1; function matchesId(action) { return action.id === value; } } }); })(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.js0000664000175100017510000005033715033037474032247 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function () { 'use strict'; /** * @ngdoc overview * @name horizon.dashboard.project.lbaasv2 * @description * The LBaaS v2 dashboard's top level module. */ angular .module('horizon.dashboard.project.lbaasv2', [ 'horizon.dashboard.project.lbaasv2.loadbalancers', 'horizon.dashboard.project.lbaasv2.listeners', 'horizon.dashboard.project.lbaasv2.l7policies', 'horizon.dashboard.project.lbaasv2.l7rules', 'horizon.dashboard.project.lbaasv2.pools', 'horizon.dashboard.project.lbaasv2.members', 'horizon.dashboard.project.lbaasv2.healthmonitors', 'horizon.framework.conf', 'horizon.framework.widgets', 'horizon.framework.util', 'horizon.app.core' ]) .config(config) .constant('horizon.dashboard.project.lbaasv2.patterns', { /* eslint-disable max-len */ ipv4: '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$', ipv6: '^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?$', /* eslint-enable max-len */ // HTTP status codes - a single number, comma separated numbers, or a range of numbers. httpStatusCodes: /^\d+((\s*-\s*\d+)|(\s*,\s*\d+)+)?$/, // URL path - must start with "/" and can include anything after that urlPath: /^((\/)|(\/[^/]+)+)$/ }) .constant('horizon.dashboard.project.lbaasv2.popovers', { ipAddresses: '
  • {$ addr.ip $}
' }) .constant('horizon.dashboard.project.lbaasv2.events', events()) .run(['$rootScope', '$location', function ($rootScope, $location) { $rootScope.$on('$routeChangeError', function() { $location.path('project/load_balancer'); }); }]); config.$inject = [ '$provide', '$windowProvider', '$routeProvider' ]; function events() { return { ACTION_DONE: 'horizon.dashboard.project.lbaasv2.ACTION_DONE' }; } function config($provide, $windowProvider, $routeProvider) { var basePath = $windowProvider.$get().STATIC_URL + 'dashboard/project/lbaasv2/'; $provide.constant('horizon.dashboard.project.lbaasv2.basePath', basePath); var loadbalancers = '/project/load_balancer'; var listener = loadbalancers + '/:loadbalancerId/listeners/:listenerId'; var listenerL7Policy = listener + '/l7policies/:l7policyId'; var listenerL7Rule = listenerL7Policy + '/l7rules/:l7ruleId'; var listenerPool = listener + '/pools/:poolId'; var listenerPoolMember = listenerPool + '/members/:memberId'; var listenerPoolHealthmonitor = listenerPool + '/healthmonitors/:healthmonitorId'; var loadbalancerPool = loadbalancers + '/:loadbalancerId/pools/:poolId'; var loadbalancerPoolMember = loadbalancerPool + '/members/:memberId'; var loadbalancerPoolHealthmonitor = loadbalancerPool + '/healthmonitors/:healthmonitorId'; $routeProvider .when(loadbalancers, { templateUrl: basePath + 'loadbalancers/panel.html', controller: 'PanelController', controllerAs: 'ctrl' }) .when(loadbalancers + '/:loadbalancerId', { templateUrl: basePath + 'loadbalancers/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ] }, controller: 'LoadBalancerDetailController', controllerAs: 'ctrl' }) .when(listener, { templateUrl: basePath + 'listeners/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ], listener: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getListener($route.current.params.listenerId).then( function success(response) { response.data.loadbalancerId = $route.current.params.loadbalancerId; return response.data; } ); } ] }, controller: 'ListenerDetailController', controllerAs: 'ctrl' }) .when(listenerL7Policy, { templateUrl: basePath + 'l7policies/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ], listener: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getListener($route.current.params.listenerId).then( function success(response) { return response.data; } ); } ], l7policy: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getL7Policy($route.current.params.l7policyId).then( function success(response) { response.data.loadbalancerId = $route.current.params.loadbalancerId; response.data.listenerId = $route.current.params.listenerId; return response.data; } ); } ] }, controller: 'L7PolicyDetailController', controllerAs: 'ctrl' }) .when(listenerL7Rule, { templateUrl: basePath + 'l7rules/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ], listener: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getListener($route.current.params.listenerId).then( function success(response) { return response.data; } ); } ], l7policy: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getL7Policy($route.current.params.l7policyId).then( function success(response) { return response.data; } ); } ], l7rule: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getL7Rule($route.current.params.l7policyId, $route.current.params.l7ruleId).then( function success(response) { response.data.loadbalancerId = $route.current.params.loadbalancerId; response.data.listenerId = $route.current.params.listenerId; response.data.l7policyId = $route.current.params.l7policyId; return response.data; } ); } ] }, controller: 'L7RuleDetailController', controllerAs: 'ctrl' }) .when(listenerPool, { templateUrl: basePath + 'pools/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ], listener: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getListener($route.current.params.listenerId).then( function success(response) { return response.data; } ); } ], pool: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getPool($route.current.params.poolId).then( function success(response) { response.data.loadbalancerId = $route.current.params.loadbalancerId; response.data.listenerId = $route.current.params.listenerId; return response.data; } ); } ] }, controller: 'PoolDetailController', controllerAs: 'ctrl' }) .when(listenerPoolMember, { templateUrl: basePath + 'members/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ], listener: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getListener($route.current.params.listenerId).then( function success(response) { return response.data; } ); } ], pool: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getPool($route.current.params.poolId).then( function success(response) { return response.data; } ); } ], member: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getMember($route.current.params.poolId, $route.current.params.memberId).then( function success(response) { response.data.loadbalancerId = $route.current.params.loadbalancerId; response.data.listenerId = $route.current.params.listenerId; response.data.poolId = $route.current.params.poolId; return response.data; } ); } ] }, controller: 'MemberDetailController', controllerAs: 'ctrl' }) .when(listenerPoolHealthmonitor, { templateUrl: basePath + 'healthmonitors/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ], listener: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getListener($route.current.params.listenerId).then( function success(response) { return response.data; } ); } ], pool: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getPool($route.current.params.poolId).then( function success(response) { return response.data; } ); } ], healthmonitor: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getHealthMonitor( $route.current.params.healthmonitorId).then( function success(response) { response.data.loadbalancerId = $route.current.params.loadbalancerId; response.data.listenerId = $route.current.params.listenerId; response.data.poolId = $route.current.params.poolId; return response.data; } ); } ] }, controller: 'HealthMonitorDetailController', controllerAs: 'ctrl' }) .when(loadbalancerPool, { templateUrl: basePath + 'pools/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ], listener: function() { return {}; }, pool: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getPool($route.current.params.poolId).then( function success(response) { response.data.loadbalancerId = $route.current.params.loadbalancerId; response.data.listenerId = $route.current.params.listenerId; return response.data; } ); } ] }, controller: 'PoolDetailController', controllerAs: 'ctrl' }) .when(loadbalancerPoolMember, { templateUrl: basePath + 'members/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ], listener: function() { return {}; }, pool: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getPool($route.current.params.poolId).then( function success(response) { return response.data; } ); } ], member: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getMember($route.current.params.poolId, $route.current.params.memberId).then( function success(response) { response.data.loadbalancerId = $route.current.params.loadbalancerId; response.data.listenerId = $route.current.params.listenerId; response.data.poolId = $route.current.params.poolId; return response.data; } ); } ] }, controller: 'MemberDetailController', controllerAs: 'ctrl' }) .when(loadbalancerPoolHealthmonitor, { templateUrl: basePath + 'healthmonitors/details/detail.html', resolve: { loadbalancer: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getLoadBalancer($route.current.params.loadbalancerId, true).then( function success(response) { response.data.floating_ip_address = response.data.floating_ip.ip; return response.data; } ); } ], listener: function() { return {}; }, pool: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getPool($route.current.params.poolId).then( function success(response) { return response.data; } ); } ], healthmonitor: [ '$route', 'horizon.app.core.openstack-service-api.lbaasv2', function($route, api) { return api.getHealthMonitor( $route.current.params.healthmonitorId).then( function success(response) { response.data.loadbalancerId = $route.current.params.loadbalancerId; response.data.listenerId = $route.current.params.listenerId; response.data.poolId = $route.current.params.poolId; return response.data; } ); } ] }, controller: 'HealthMonitorDetailController', controllerAs: 'ctrl' }); } }()); ././@PaxHeader0000000000000000000000000000020700000000000010214 xustar00113 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.spec0000664000175100017510000005035115033037474032561 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Module', function () { it('should be defined', function () { expect(angular.module('horizon.dashboard.project.lbaasv2')).toBeDefined(); }); }); describe('LBaaS v2 Module Base Path', function () { var basePath, staticUrl; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function ($injector) { basePath = $injector.get('horizon.dashboard.project.lbaasv2.basePath'); staticUrl = $injector.get('$window').STATIC_URL; })); it('should be defined', function () { expect(basePath).toBeDefined(); }); it('should be correct', function () { expect(basePath).toEqual(staticUrl + 'dashboard/project/lbaasv2/'); }); }); describe('LBaaS v2 Module Constants', function () { var patterns, popovers; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function ($injector) { patterns = $injector.get('horizon.dashboard.project.lbaasv2.patterns'); popovers = $injector.get('horizon.dashboard.project.lbaasv2.popovers'); })); it('should define patterns', function () { expect(patterns).toBeDefined(); }); it('should define expected patterns', function () { expect(Object.keys(patterns).length).toBe(4); var keys = ['ipv4', 'ipv6', 'httpStatusCodes', 'urlPath']; angular.forEach(keys, function(key) { expect(patterns[key]).toBeDefined(); }); }); it('should define correct pattern for health monitor status codes', function () { expect(Object.keys(patterns).length).toBe(4); var regex = patterns.httpStatusCodes; expect(regex.test('200')).toBe(true); expect(regex.test('200-204')).toBe(true); expect(regex.test('200,203,204')).toBe(true); expect(regex.test('foo')).toBe(false); expect(regex.test('200,202-204')).toBe(false); }); it('should define popovers', function () { expect(popovers).toBeDefined(); }); it('should define expected popover templates', function () { expect(Object.keys(popovers).length).toBe(1); var keys = ['ipAddresses']; angular.forEach(keys, function(key) { expect(popovers[key]).toBeDefined(); }); }); }); describe('LBaaS v2 Module Config', function () { var $routeProvider, basePath; // eslint-disable-line no-unused-vars beforeEach(function() { // Create a dummy module so that we can test $routeProvider calls in our actual // config block. angular.module('configTest', []) .config(function(_$routeProvider_, $windowProvider) { $routeProvider = _$routeProvider_; basePath = $windowProvider.$get().STATIC_URL + 'dashboard/project/lbaasv2/'; spyOn($routeProvider, 'when').and.callThrough(); }); module('ngRoute'); module('configTest'); module('horizon.dashboard.project.lbaasv2'); inject(); }); it('should route resolved loadbalancer panel', inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/loadbalancers/panel.html' ).respond({}); $location.path('/project/load_balancer/'); $rootScope.$digest(); expect($route.current).toBeDefined(); }) ); it('should route resolved loadbalancer detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/loadbalancers/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should route resolved listener detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } function listenerAPI() { var listener = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(listener); }, then: function(callback) { callback({ data: { id: 1}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getListener').and.callFake(listenerAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/listeners/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1/listeners/2'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should route resolved listener pool detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } function listenerAPI() { var listener = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(listener); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function poolAPI() { var pool = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(pool); }, then: function(callback) { callback({ data: { id: 1}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getListener').and.callFake(listenerAPI); spyOn(lbaasv2API, 'getPool').and.callFake(poolAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/pools/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1/listeners/2/pools/3'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should route resolved listener l7 policy detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } function listenerAPI() { var listener = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(listener); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function l7policyAPI() { var l7policy = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(l7policy); }, then: function(callback) { callback({ data: { id: 1}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getListener').and.callFake(listenerAPI); spyOn(lbaasv2API, 'getL7Policy').and.callFake(l7policyAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/l7policies/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1/listeners/2/l7policies/3'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should route resolved listener l7 rule detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } function listenerAPI() { var listener = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(listener); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function l7policyAPI() { var l7policy = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(l7policy); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function l7ruleAPI() { var l7rule = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(l7rule); }, then: function(callback) { callback({ data: { id: 1}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getListener').and.callFake(listenerAPI); spyOn(lbaasv2API, 'getL7Policy').and.callFake(l7policyAPI); spyOn(lbaasv2API, 'getL7Rule').and.callFake(l7ruleAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/l7rules/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1/listeners/2/l7policies/3/l7rules/4'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should route resolved listener pool member detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } function listenerAPI() { var listener = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(listener); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function poolAPI() { var pool = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(pool); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function memberAPI() { var member = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(member); }, then: function(callback) { callback({ data: { id: 1}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getListener').and.callFake(listenerAPI); spyOn(lbaasv2API, 'getPool').and.callFake(poolAPI); spyOn(lbaasv2API, 'getMember').and.callFake(memberAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/members/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1/listeners/2/pools/3/members/4'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should route resolved listener pool health monitor detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } function listenerAPI() { var listener = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(listener); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function poolAPI() { var pool = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(pool); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function healthmonitorAPI() { var healthmonitor = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(healthmonitor); }, then: function(callback) { callback({ data: { id: 1}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getListener').and.callFake(listenerAPI); spyOn(lbaasv2API, 'getPool').and.callFake(poolAPI); spyOn(lbaasv2API, 'getHealthMonitor').and.callFake(healthmonitorAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/healthmonitors/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1/listeners/2/pools/3/healthmonitors/4'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should route resolved loadbalancer pool detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } function poolAPI() { var pool = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(pool); }, then: function(callback) { callback({ data: { id: 1}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getPool').and.callFake(poolAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/pools/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1/pools/3'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should route resolved loadbalancer pool member detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } function poolAPI() { var pool = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(pool); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function memberAPI() { var member = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(member); }, then: function(callback) { callback({ data: { id: 1}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getPool').and.callFake(poolAPI); spyOn(lbaasv2API, 'getMember').and.callFake(memberAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/members/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1/pools/3/members/4'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should route resolved loadbalancer pool health monitor detail', inject(function($injector) { function loadbalancerAPI() { var loadbalancer = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(loadbalancer); }, then: function(callback) { callback({ data: { id: 1, floating_ip: {}}}); } }; } function poolAPI() { var pool = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(pool); }, then: function(callback) { callback({ data: { id: 1}}); } }; } function healthmonitorAPI() { var healthmonitor = { provisioning_status: 'ACTIVE' }; return { success: function(callback) { callback(healthmonitor); }, then: function(callback) { callback({ data: { id: 1}}); } }; } var lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); spyOn(lbaasv2API, 'getLoadBalancer').and.callFake(loadbalancerAPI); spyOn(lbaasv2API, 'getPool').and.callFake(poolAPI); spyOn(lbaasv2API, 'getHealthMonitor').and.callFake(healthmonitorAPI); inject(function($route, $location, $rootScope, $httpBackend) { $httpBackend.expectGET( '/static/dashboard/project/lbaasv2/healthmonitors/details/detail.html' ).respond({}); $location.path('/project/load_balancer/1/pools/3/healthmonitors/4'); $rootScope.$digest(); expect($route.current).toBeDefined(); }); })); it('should redirect to project home on route change error', inject(function($location, $rootScope) { spyOn($location, 'path').and.callThrough(); $rootScope.$emit('$routeChangeError', null, null, null, 'routeChangeError'); expect($location.path).toHaveBeenCalledWith('project/load_balancer'); }) ); }); })(); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.scss0000664000175100017510000000573615033037474031325 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * Copyright 2017 Walmart. * * 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. */ /* Load Balancer Wizard */ .lbaas-wizard { /* Field widths for editable inputs in the members table */ table { .member-weight, .member-port { width: 6em; } .member-address { width: 18em; } .member-monitor-port { width: 6em; } .member-monitor-address { width: 18em; } } /* The IP addresses list displayed when hovering over the IP address in the available instances table, and any lists in the help panels. */ .addresses-popover + .popover, #help-panel { ul { list-style-type: disc; padding-left: 10px; } } /* Pool Members tab */ [ng-form="memberDetailsForm"] { .transfer-section:first-child { /* Remove the borders around the last row in the top table that has the "Add external member" action in it. */ .table-rsp.table-detail tbody tr:nth-last-child(2):not(.expanded) td, .table-rsp.table-detail tbody tr:last-child:not(.spacer-row) td { border-bottom: none; } /* Remove the striped background on the last row in the top table that has the "Add external member" action in it. */ .table-rsp.table-detail.table-striped tbody tr:last-child > td { background: none; } td { /* So the input fields fit better in the table row */ .form-group { margin-bottom: 0px; } } } .transfer-section:last-child { /* Hide the badge on the bottom table with the instance count. */ .transfer-heading .badge { display: none; } } } } /* Progress indicator in the table while items are loading */ [table-status] { .progress { margin: 0px auto; width: 25%; height: $line-height-computed; .progress-bar { width: 100%; } } } .octavia-tabset { .tab-content { margin-top: 10px; } } /* Filtering select widget */ .filter-select-options { padding: 10px; background-color: $dropdown-bg; min-width: 100%; thead { th { color: $dropdown-header-color; } } tbody { tr:hover { color: $dropdown-link-hover-color; background-color: $dropdown-link-hover-bg; } tr { color:$dropdown-link-color; .highlighted { background-color: darken($dropdown-link-hover-bg, 15%); } .empty-options { text-align: center; font-style: italic; } } } } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4681008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/0000775000175100017510000000000015033037476031075 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.456101 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/0000775000175100017510000000000015033037476032535 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022000000000000010207 xustar00116 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/ 28 mtime=1751924542.4681008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000775000175100017510000000000015033037476032700 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023300000000000010213 xustar00133 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/create.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000664000175100017510000000431115033037474032677 0ustar00mylesmyles/* * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.listeners') .factory('horizon.dashboard.project.lbaasv2.listeners.actions.create', createService); createService.$inject = [ 'horizon.dashboard.project.lbaasv2.listeners.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc service * @ngname horizon.dashboard.project.lbaasv2.listeners.actions.batchActions * * @description * Provides the service for the Listeners creation. * * @param resourceType The listener resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns Listeners create service object. */ function createService( resourceType, actionResultService, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'CreateListenerWizardController', message: gettext('A new listener is being created.'), handle: handle, allowed: allowed }); function allowed() { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:listener:post']] }); } function handle(response) { return actionResultService.getActionResult() .created(resourceType, response.data.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000024000000000000010211 xustar00138 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/create.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000664000175100017510000000347615033037474032712 0ustar00mylesmyles/* * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Create Listener Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'listener1' } }); } } }; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.listeners.actions.create'); })); it('should check policy to allow creating a listener', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); expect(service.allowed()).toBe(true); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [[ 'load-balancer', 'os_load-balancer_api:listener:post' ]] } ); }); it('should handle the action result properly', function() { var result = service.handle({data: {id: 1}}); expect(result.created[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000023600000000000010216 xustar00136 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000664000175100017510000000275215033037474032706 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.listeners') .controller('CreateListenerWizardController', CreateListenerWizardController); CreateListenerWizardController.$inject = [ '$scope', '$routeParams', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; function CreateListenerWizardController($scope, $routeParams, model, workflowService, gettext) { var loadbalancerId = $routeParams.loadbalancerId; var scope = $scope; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Create Listener'), 'fa fa-cloud-download', ['listener', 'certificates', 'pool', 'members', 'monitor'] ); scope.model.initialize('listener', false, loadbalancerId); } })(); ././@PaxHeader0000000000000000000000000000024300000000000010214 xustar00141 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000664000175100017510000000353515033037474032706 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Create Listener Wizard Controller', function() { var ctrl; var model = { submit: function() { return 'created'; }, initialize: angular.noop }; var workflow = function() { return 'foo'; }; var scope = {}; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow); })); beforeEach(inject(function ($controller) { spyOn(model, 'initialize'); ctrl = $controller('CreateListenerWizardController', { $scope: scope }); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalled(); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe('foo'); }); it('defines scope.submit', function() { expect(scope.submit).toBeDefined(); expect(scope.submit()).toBe('created'); }); }); })(); ././@PaxHeader0000000000000000000000000000022000000000000010207 xustar00116 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/delete/ 28 mtime=1751924542.4691007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/d0000775000175100017510000000000015033037476032701 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024200000000000010213 xustar00140 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/delete/delete.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/d0000664000175100017510000001015515033037474032703 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.listeners') .factory('horizon.dashboard.project.lbaasv2.listeners.actions.delete', deleteService); deleteService.$inject = [ 'horizon.dashboard.project.lbaasv2.listeners.resourceType', 'horizon.framework.util.actions.action-result.service', '$q', '$location', 'horizon.framework.widgets.modal.deleteModalService', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.app.core.openstack-service-api.policy' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.listeners.actions.deleteService * * @description * Brings up the delete listeners confirmation modal dialog. * On submit, deletes selected listeners. * On cancel, does nothing. * * @param resourceType The listener resource type. * @param actionResultService The horizon action result service. * @param $q The angular service for promises. * @param $location The angular $location service. * @param deleteModal The horizon delete modal service. * @param api The LBaaS v2 API service. * @param policy The horizon policy service. * * @returns The listeners delete service. */ function deleteService( resourceType, actionResultService, $q, $location, deleteModal, api, policy ) { var loadbalancerId, scope; var context = { }; var service = { perform: perform, allowed: allowed }; return service; ////////////// function perform(items, _scope_) { scope = _scope_; var listeners = angular.isArray(items) ? items : [items]; context.labels = labelize(listeners.length); context.deleteEntity = deleteItem; listeners.map(function(item) { loadbalancerId = item.loadbalancerId; }); return deleteModal.open(scope, listeners, context).then(deleteResult); } function labelize(count) { return { title: ngettext( 'Confirm Delete Listener', 'Confirm Delete Listeners', count), message: ngettext( 'You have selected "%s". Deleted listener is not recoverable.', 'You have selected "%s". Deleted listeners are not recoverable.', count), submit: ngettext( 'Delete Listener', 'Delete Listeners', count), success: ngettext( 'Deleted Listener: %s.', 'Deleted Listeners: %s.', count), error: ngettext( 'Unable to delete Listener: %s.', 'Unable to delete Listeners: %s.', count) }; } function deleteResult(deleteModalResult) { // To make the result of this action generically useful, reformat the return // from the deleteModal into a standard form var actionResult = actionResultService.getActionResult(); deleteModalResult.pass.forEach(function markDeleted(item) { actionResult.deleted(resourceType, item.context.id); }); deleteModalResult.fail.forEach(function markFailed(item) { actionResult.failed(resourceType, item.context.id); }); if (actionResult.result.failed.length === 0 && actionResult.result.deleted.length > 0) { var path = 'project/load_balancer/' + loadbalancerId; $location.path(path); } return actionResult.result; } function allowed() { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:listener:delete']] }); } function deleteItem(id) { return api.deleteListener(id, true); } } })(); ././@PaxHeader0000000000000000000000000000024700000000000010220 xustar00145 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/delete/delete.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/d0000664000175100017510000001234415033037474032705 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Listeners Delete Service', function() { var service, policy, modal, lbaasv2Api, $scope, $location, $q, toast, items, path; function allowed(item) { spyOn(policy, 'ifAllowed').and.returnValue(true); var allowed = service.allowed(item); $scope.$apply(); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [[ 'load-balancer', 'os_load-balancer_api:listener:delete' ]] } ); return allowed; } function makePromise(reject) { var def = $q.defer(); def[reject ? 'reject' : 'resolve'](); return def.promise; } beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.framework.conf')); beforeEach(module('horizon.framework.widgets')); beforeEach(module('horizon.app.core.openstack-service-api')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(function() { items = [{ id: '1', name: 'First', loadbalancerId: 1 }, { id: '2', name: 'Second', loadbalancerId: 1 }]; }); beforeEach(module(function($provide) { $provide.value('$uibModal', { open: function() { return { result: { then: function(func) { return func({ data: { id: 'listener1' } }); } } }; } }); $provide.value('horizon.app.core.openstack-service-api.lbaasv2', { deleteListener: function() { return makePromise(); } }); $provide.value('$location', { path: function() { return path; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); lbaasv2Api = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); modal = $injector.get('horizon.framework.widgets.modal.deleteModalService'); $scope = $injector.get('$rootScope').$new(); $location = $injector.get('$location'); $q = $injector.get('$q'); toast = $injector.get('horizon.framework.widgets.toast.service'); service = $injector.get('horizon.dashboard.project.lbaasv2.listeners.actions.delete'); })); it('should have the "allowed" and "perform" functions', function() { expect(service.allowed).toBeDefined(); expect(service.perform).toBeDefined(); }); it('should check policy to allow deleting a listener (single)', function() { expect(allowed(items[0])).toBe(true); }); it('should check policy to allow deleting a listener (batch)', function() { expect(allowed()).toBe(true); }); it('should open the delete modal', function() { spyOn(modal, 'open').and.callThrough(); service.perform(items[0], $scope); $scope.$apply(); expect(modal.open.calls.count()).toBe(1); var args = modal.open.calls.argsFor(0); expect(args.length).toBe(3); expect(args[0]).toEqual($scope); expect(args[1]).toEqual([jasmine.objectContaining({ id: '1' })]); expect(args[2]).toEqual(jasmine.objectContaining({ labels: jasmine.any(Object), deleteEntity: jasmine.any(Function) })); expect(args[2].labels.title).toBe('Confirm Delete Listener'); }); it('should pass function to modal that deletes listeners', function() { spyOn(modal, 'open').and.callThrough(); spyOn(lbaasv2Api, 'deleteListener').and.callThrough(); service.perform(items[0], $scope); $scope.$apply(); expect(lbaasv2Api.deleteListener.calls.count()).toBe(1); expect(lbaasv2Api.deleteListener).toHaveBeenCalledWith('1', true); }); it('should show message if any items fail to be deleted', function() { spyOn(modal, 'open').and.callThrough(); spyOn(lbaasv2Api, 'deleteListener').and.returnValue(makePromise(true)); spyOn(toast, 'add'); items.splice(1, 1); service.perform(items, $scope); $scope.$apply(); expect(modal.open).toHaveBeenCalled(); expect(lbaasv2Api.deleteListener.calls.count()).toBe(1); expect(toast.add).toHaveBeenCalledWith('error', 'Unable to delete Listener' + ': First.'); }); it('should return to table after delete if on detail page', function() { path = 'project/load_balancer/1/listeners/2'; spyOn($location, 'path'); spyOn(toast, 'add'); service.perform(items[0], $scope); $scope.$apply(); expect($location.path).toHaveBeenCalledWith('project/load_balancer/1'); expect(toast.add).toHaveBeenCalledWith('success', 'Deleted Listener: First.'); }); }); })(); ././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00114 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/ 28 mtime=1751924542.4691007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000775000175100017510000000000015033037476032702 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022700000000000010216 xustar00129 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/edit.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000664000175100017510000000432315033037474032704 0ustar00mylesmyles/* * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.listeners') .factory('horizon.dashboard.project.lbaasv2.listeners.actions.edit', editService); editService.$inject = [ 'horizon.dashboard.project.lbaasv2.listeners.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc service * @ngname horizon.dashboard.project.lbaasv2.listeners.actions.edit * * @description * Provides the service for the Listener edit action. * * @param resourceType The listener resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns Listeners edit action service object. */ function editService( resourceType, actionResultService, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'EditListenerWizardController', message: gettext('The listener has been updated.'), handle: handle, allowed: allowed }); function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:listener:put']] }); } function handle(response) { return actionResultService.getActionResult() .updated(resourceType, response.config.data.listener.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00134 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/edit.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000664000175100017510000000351615033037474032707 0ustar00mylesmyles/* * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Edit Listener Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'listener1' } }); } } }; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.listeners.actions.edit'); })); it('should check policy to allow editing a listener', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); expect(service.allowed()).toBe(true); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [[ 'load-balancer', 'os_load-balancer_api:listener:put' ]] } ); }); it('should handle the action result properly', function() { var result = service.handle({config: {data: {listener: {id: 1}}}}); expect(result.updated[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00134 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000664000175100017510000000371015033037474032703 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .controller('EditListenerWizardController', EditListenerWizardController); EditListenerWizardController.$inject = [ '$scope', '$q', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name EditListenerWizardController * * @description * Controller for the LBaaS v2 edit listener wizard. * * @param $scope The angular scope object. * @param $q The angular service for promises. * @param model The LBaaS V2 workflow model service. * @param workflowService The LBaaS V2 workflow service. * @param gettext The horizon gettext function for translation. * @returns undefined */ function EditListenerWizardController($scope, $q, model, workflowService, gettext) { var scope = $scope; var steps = ['listener']; var protocol = scope.launchContext.protocol; if (protocol === 'TERMINATED_HTTPS') { steps = ['listener', 'certificates']; } scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Update Listener'), 'fa fa-pencil', steps); scope.model.initialize('listener', scope.launchContext.id); } })(); ././@PaxHeader0000000000000000000000000000024100000000000010212 xustar00139 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000664000175100017510000000511115033037474032700 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Edit Listener Wizard Controller', function() { var ctrl, workflowSpy, $q, scope; var model = { submit: function() { return 'updated'; }, initialize: function() { var defer = $q.defer(); defer.resolve(); return defer.promise; } }; var workflow = { steps: [{id: 'listener'}], append: angular.noop }; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { workflowSpy = jasmine.createSpy('workflow').and.returnValue(workflow); $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflowSpy); })); beforeEach(inject(function ($controller, $injector) { $q = $injector.get('$q'); scope = $injector.get('$rootScope').$new(); scope.launchContext = { id: '1234' }; spyOn(model, 'initialize').and.callThrough(); ctrl = $controller('EditListenerWizardController', { $scope: scope }); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalledWith('listener', '1234'); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe(workflow); }); it('initializes workflow with correct properties', inject(function($controller) { scope.launchContext = { id: '1234', protocol: 'TERMINATED_HTTPS' }; ctrl = $controller('EditListenerWizardController', { $scope: scope }); expect(workflowSpy).toHaveBeenCalledWith('Update Listener', 'fa fa-pencil', jasmine.any(Object)); })); it('defines scope.submit', function() { expect(scope.submit).toBe(model.submit); expect(scope.submit()).toBe('updated'); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4691007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/0000775000175100017510000000000015033037476032522 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022700000000000010216 xustar00129 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/d0000664000175100017510000001100415033037474032662 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.listeners') .controller('ListenerDetailController', ListenerDetailController); ListenerDetailController.$inject = [ '$timeout', 'horizon.dashboard.project.lbaasv2.events', '$scope', 'loadbalancer', 'listener', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.listeners.resourceType', 'horizon.framework.conf.resource-type-registry.service', 'horizon.framework.widgets.modal-wait-spinner.service', '$q' ]; /** * @ngdoc controller * @name ListenerDetailController * * @description * Controller for the LBaaS v2 listener detail page. * * @param $scope The angular scope object. * @param loadbalancer The loadbalancer object. * @param listener The listener object. * @param loadBalancersService The LBaaS v2 load balancers service. * @param resourceType The listenr resource type. * @param typeRegistry The horizon resource type registry service. * @param spinnerService The horizon modal wait spinner service. * @param $q The angular service for promises. * * @returns undefined */ function ListenerDetailController( $timeout, events, $scope, loadbalancer, listener, loadBalancersService, resourceType, typeRegistry, spinnerService, $q ) { var ctrl = this; ctrl.operatingStatus = loadBalancersService.operatingStatus; ctrl.provisioningStatus = loadBalancersService.provisioningStatus; ctrl.loadbalancer = loadbalancer; ctrl.listener = listener; ctrl.listFunctionExtraParams = { loadbalancerId: ctrl.loadbalancer.id, listenerId: ctrl.listener.id }; ctrl.resourceType = typeRegistry.getResourceType(resourceType); ctrl.context = {}; ctrl.context.identifier = listener.id; ctrl.resultHandler = actionResultHandler; $scope.$watch( function() { return ctrl.listener; }, function() { $timeout.cancel($scope.loadTimeout); $scope.loadTimeout = $timeout(function() { ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); }, loadBalancersService.backoff.duration()); } ); $scope.$on( events.ACTION_DONE, function() { loadBalancersService.backoff.reset(); ctrl.listener = angular.copy(ctrl.listener); } ); $scope.$on( '$destroy', function() { $timeout.cancel($scope.loadTimeout); } ); function actionResultHandler(returnValue) { return $q.when(returnValue, actionSuccessHandler); } function loadData(response) { spinnerService.hideModalSpinner(); ctrl.showDetails = true; ctrl.resourceType.initActions(); ctrl.listener = response.data; ctrl.listener.loadbalancerId = ctrl.loadbalancer.id; ctrl.listFunctionExtraParams = { loadbalancerId: ctrl.loadbalancer.id, listenerId: ctrl.listener.id }; } function actionSuccessHandler(result) { // The action has completed (for whatever "complete" means to that // action. Notice the view doesn't really need to know the semantics of the // particular action because the actions return data in a standard form. // That return includes the id and type of each created, updated, deleted // and failed item. // Currently just refreshes the display each time. if (result) { if (result.failed.length === 0 && result.deleted.length > 0) { // handle a race condition where the resource is already deleted return; } spinnerService.showModalSpinner(gettext('Please Wait')); ctrl.showDetails = false; ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); } } } })(); ././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00134 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/d0000664000175100017510000001105215033037474032665 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Listener Detail Controller', function() { var deferred, service, ctrl, scope, $timeout, $q, actionResultService; /////////////////////// beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModal', {}); })); beforeEach(inject(function($controller, $rootScope, _$q_, _$timeout_) { $q = _$q_; deferred = $q.defer(); service = { getResourceType: function() { return { load: function() { return deferred.promise; }, parsePath: function() { return 'my-context'; }, itemName: function() { return 'A name'; }, initActions: angular.noop }; }, getDefaultDetailsTemplateUrl: angular.noop }; actionResultService = { getIdsOfType: function() { return []; } }; $timeout = _$timeout_; scope = $rootScope.$new(); ctrl = $controller('ListenerDetailController', { $scope: scope, loadbalancer: { id: '123' }, listener: { id: '123', provisioning_status: 'ACTIVE' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); })); it('should create a controller', function() { expect(ctrl).toBeDefined(); expect(ctrl.loadbalancer).toBeDefined(); expect(ctrl.listener).toBeDefined(); }); describe('data watchers', function() { var events, loadBalancersService; beforeEach(inject(function($injector) { events = $injector.get('horizon.dashboard.project.lbaasv2.events'); loadBalancersService = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.service' ); })); it('should refresh on provisioning status change', function() { var loadFunctionDeferred = $q.defer(); spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise); ctrl.listener = { id: '123', provisioning_status: 'PENDING_UPDATE' }; scope.$apply(); $timeout.flush(); expect(ctrl.resourceType.load).toHaveBeenCalled(); spyOn(loadBalancersService.backoff, 'reset').and.callThrough(); scope.$broadcast(events.ACTION_DONE); expect(loadBalancersService.backoff.reset).toHaveBeenCalled(); }); }); describe('resultHandler', function() { it('handles empty results', function() { var result = $q.defer(); result.resolve({failed: [], deleted: []}); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles falsy results', function() { var result = $q.defer(); result.resolve(false); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles matched results', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: []}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(true); }); it('handles delete race condition', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(undefined); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00120 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/d0000664000175100017510000000567615033037474032704 0ustar00mylesmyles
././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00120 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/drawer.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/d0000664000175100017510000000067215033037474032673 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00120 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners.module.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners0000664000175100017510000001254115033037474033031 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; /** * @ngdoc overview * @ngname horizon.dashboard.project.lbaasv2.listeners * * @description * Provides the services and widgets required to support and display the project listeners * for the load balancers v2 panel. */ angular .module('horizon.dashboard.project.lbaasv2.listeners', []) .constant('horizon.dashboard.project.lbaasv2.listeners.resourceType', 'OS::Octavia::Listener') .run(run); run.$inject = [ 'horizon.framework.conf.resource-type-registry.service', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.listeners.actions.create', 'horizon.dashboard.project.lbaasv2.listeners.actions.edit', 'horizon.dashboard.project.lbaasv2.listeners.actions.delete', 'horizon.dashboard.project.lbaasv2.listeners.resourceType' ]; function run( registry, basePath, loadBalancerService, createService, editService, deleteService, resourceType ) { var listenerResourceType = registry.getResourceType(resourceType); listenerResourceType .setNames(gettext('Listener'), gettext('Listeners')) .setSummaryTemplateUrl(basePath + 'listeners/details/drawer.html') .setProperties(listenerProperties(loadBalancerService)) .setListFunction(loadBalancerService.getListenersPromise) .setLoadFunction(loadBalancerService.getListenerPromise) .tableColumns .append({ id: 'name', priority: 1, sortDefault: true, urlFunction: loadBalancerService.getListenerDetailsPath }) .append({ id: 'protocol', priority: 1 }) .append({ id: 'protocol_port', priority: 1 }) .append({ id: 'operating_status', priority: 1 }) .append({ id: 'provisioning_status', priority: 1 }) .append({ id: 'admin_state_up', priority: 1 }); listenerResourceType.itemActions .append({ id: 'listenerEdit', service: editService, template: { text: gettext('Edit Listener') } }) .append({ id: 'listenerDelete', service: deleteService, template: { text: gettext('Delete Listener'), type: 'delete' } }); listenerResourceType.globalActions .append({ id: 'listenerCreate', service: createService, template: { type: 'create', text: gettext('Create Listener') } }); listenerResourceType.batchActions .append({ id: 'listenerBatchDelete', service: deleteService, template: { text: gettext('Delete Listeners'), type: 'delete-selected' } }); } function listenerProperties(loadBalancerService) { return { id: gettext('ID'), name: { label: gettext('Name'), filters: ['noName'] }, description: { label: gettext('Description'), filters: ['noName'] }, provisioning_status: { label: gettext('Provisioning Status'), values: loadBalancerService.provisioningStatus }, operating_status: { label: gettext('Operating Status'), values: loadBalancerService.operatingStatus }, admin_state_up: { label: gettext('Admin State Up'), filters: ['yesno'] }, protocol: gettext('Protocol'), protocol_port: gettext('Port'), project_id: gettext('Project ID'), created_at: { label: gettext('Created At'), filters: ['noValue'] }, updated_at: { label: gettext('Updated At'), filters: ['noValue'] }, connection_limit: { label: gettext('Connection Limit'), filters: ['limit'] }, default_tls_container_ref: gettext('Default TLS Container Ref'), sni_container_refs: gettext('SNI Container Refs'), default_pool_id: { label: gettext('Default Pool ID'), filters: ['noValue'] }, l7_policies: gettext('L7 Policies'), insert_headers: { label: gettext('Insert Headers'), filters: [ 'json', loadBalancerService.nullFilter ] }, allowed_cidrs: { label: gettext('Allowed Cidrs'), filters: ['noValue'] }, timeout_client_data: gettext('Client Data Timeout'), timeout_member_connect: gettext('Member Connect Timeout'), timeout_member_data: gettext('Member Data Timeout'), timeout_tcp_inspect: gettext('TCP Inspect Timeout'), load_balancers: gettext('Load Balancers'), tls_ciphers: gettext('TLS Cipher String') }; } })(); ././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners.module.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners0000664000175100017510000000422615033037474033032 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Listeners Module', function() { it('should exist', function() { expect(angular.module('horizon.dashboard.project.lbaasv2.listeners')).toBeDefined(); }); }); describe('LBaaS v2 Listeners Registry', function () { var registry, resourceType; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function($injector) { resourceType = $injector.get('horizon.dashboard.project.lbaasv2.listeners.resourceType'); registry = $injector.get('horizon.framework.conf.resource-type-registry.service'); })); it('should define resourceType', function () { expect(resourceType).toBeDefined(); }); it('should register item actions', function () { var actions = registry.getResourceType(resourceType).itemActions; expect(actionHasId(actions, 'listenerEdit')).toBe(true); expect(actionHasId(actions, 'listenerDelete')).toBe(true); }); it('should register global actions', function () { var actions = registry.getResourceType(resourceType).globalActions; expect(actionHasId(actions, 'listenerCreate')).toBe(true); }); it('should register batch actions', function () { var actions = registry.getResourceType(resourceType).batchActions; expect(actionHasId(actions, 'listenerBatchDelete')).toBe(true); }); function actionHasId(list, value) { return list.filter(matchesId).length === 1; function matchesId(action) { return action.id === value; } } }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4691007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/0000775000175100017510000000000015033037476031657 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000021500000000000010213 xustar00113 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/ 28 mtime=1751924542.4571009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000775000175100017510000000000015033037476032677 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023200000000000010212 xustar00126 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/ 28 mtime=1751924542.4691007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000775000175100017510000000000015033037476032677 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024700000000000010220 xustar00145 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000702715033037474032705 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .controller('AssociateFloatingIpModalController', AssociateFloatingIpModalController); AssociateFloatingIpModalController.$inject = [ '$uibModalInstance', 'horizon.app.core.openstack-service-api.network', 'horizon.framework.util.i18n.gettext', // Dependencies injected with resolve by $uibModal.open 'loadbalancer', 'floatingIps', 'floatingIpPools' ]; /** * @ngdoc controller * @name AssociateFloatingIpModalController * @description * Controller used by the modal service for associating a floating IP address to a * load balancer. * * @param $uibModalInstance The angular bootstrap $uibModalInstance service. * @param api The horizon network API service. * @param gettext The horizon gettext function for translation. * @param loadbalancer The load balancer to associate the floating IP with. * @param floatingIps List of available floating IP addresses. * @param floatingIpPools List of available floating IP pools. * * @returns The Associate Floating IP modal controller. */ function AssociateFloatingIpModalController( $uibModalInstance, api, gettext, loadbalancer, floatingIps, floatingIpPools ) { var ctrl = this; var port = loadbalancer.vip_port_id + '_' + loadbalancer.vip_address; ctrl.cancel = cancel; ctrl.save = save; ctrl.saving = false; ctrl.options = initOptions(); ctrl.selected = ctrl.options.length === 1 ? ctrl.options[0] : null; function save() { ctrl.saving = true; if (ctrl.selected.type === 'pool') { allocateIpAddress(ctrl.selected.id); } else { associateIpAddress(ctrl.selected.id); } } function cancel() { $uibModalInstance.dismiss('cancel'); } function onSuccess() { $uibModalInstance.close(); } function onFailure() { ctrl.saving = false; } function initOptions() { var options = []; floatingIps.forEach(function addFloatingIp(ip) { // Only show floating IPs that are not already associated with a fixed IP if (!ip.fixed_ip) { options.push({ id: ip.id, name: ip.ip || ip.id, type: 'ip', group: gettext('Floating IP addresses') }); } }); floatingIpPools.forEach(function addFloatingIpPool(pool) { options.push({ id: pool.id, name: pool.name || pool.id, type: 'pool', group: gettext('Floating IP pools') }); }); return options; } function allocateIpAddress(poolId) { return api.allocateFloatingIp(poolId).then(getId).then(associateIpAddress); } function associateIpAddress(addressId) { return api.associateFloatingIp(addressId, port).then(onSuccess, onFailure); } function getId(response) { return response.data.id; } } })(); ././@PaxHeader0000000000000000000000000000025400000000000010216 xustar00150 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000001267015033037474032705 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Load Balancers Table Associate IP Controller', function() { var ctrl, network, floatingIps, floatingIpPools, $controller, $uibModalInstance; var associateFail = false; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(function() { floatingIps = [{ id: 'ip1', ip: '1', fixed_ip: '1' }, { id: 'ip2', ip: '2' }]; floatingIpPools = [{ id: 'pool1', name: 'pool' }]; }); beforeEach(module(function($provide) { var fakePromise = function(response, returnPromise) { return { then: function(success, fail) { if (fail && associateFail) { return fail(); } var res = success(response); return returnPromise ? fakePromise(res) : res; } }; }; $provide.value('$uibModalInstance', { close: angular.noop, dismiss: angular.noop }); $provide.value('loadbalancer', { vip_port_id: 'port', vip_address: 'address' }); $provide.value('floatingIps', floatingIps); $provide.value('floatingIpPools', floatingIpPools); $provide.value('horizon.app.core.openstack-service-api.network', { allocateFloatingIp: function() { return fakePromise({ data: { id: 'foo' } }, true); }, associateFloatingIp: function() { return fakePromise(); } }); })); beforeEach(inject(function ($injector) { network = $injector.get('horizon.app.core.openstack-service-api.network'); $controller = $injector.get('$controller'); $uibModalInstance = $injector.get('$uibModalInstance'); })); it('should define controller properties', function() { ctrl = $controller('AssociateFloatingIpModalController'); expect(ctrl.cancel).toBeDefined(); expect(ctrl.save).toBeDefined(); expect(ctrl.saving).toBe(false); }); it('should initialize options', function() { ctrl = $controller('AssociateFloatingIpModalController'); expect(ctrl.options.length).toBe(2); expect(ctrl.options[0].id).toBe('ip2'); expect(ctrl.options[1].id).toBe('pool1'); }); it('should use ids instead of ip or name if not provided', function() { delete floatingIps[1].ip; delete floatingIpPools[0].name; ctrl = $controller('AssociateFloatingIpModalController'); expect(ctrl.options.length).toBe(2); expect(ctrl.options[0].name).toBe('ip2'); expect(ctrl.options[1].name).toBe('pool1'); }); it('should initialize selected option when only one option', function() { floatingIps[1].fixed_ip = '2'; ctrl = $controller('AssociateFloatingIpModalController'); expect(ctrl.options.length).toBe(1); expect(ctrl.selected).toBe(ctrl.options[0]); }); it('should not initialize selected option when more than one option', function() { ctrl = $controller('AssociateFloatingIpModalController'); expect(ctrl.options.length).toBe(2); expect(ctrl.selected).toBeNull(); }); it('should associate floating IP if floating IP selected', function() { ctrl = $controller('AssociateFloatingIpModalController'); ctrl.selected = ctrl.options[0]; associateFail = false; spyOn(network, 'associateFloatingIp').and.callThrough(); spyOn($uibModalInstance, 'close'); ctrl.save(); expect(ctrl.saving).toBe(true); expect(network.associateFloatingIp).toHaveBeenCalledWith('ip2', 'port_address'); expect($uibModalInstance.close).toHaveBeenCalled(); }); it('should allocate floating IP if floating IP pool selected', function() { ctrl = $controller('AssociateFloatingIpModalController'); ctrl.selected = ctrl.options[1]; associateFail = false; spyOn(network, 'allocateFloatingIp').and.callThrough(); spyOn(network, 'associateFloatingIp').and.callThrough(); spyOn($uibModalInstance, 'close'); ctrl.save(); expect(ctrl.saving).toBe(true); expect(network.allocateFloatingIp).toHaveBeenCalledWith('pool1'); expect(network.associateFloatingIp).toHaveBeenCalledWith('foo', 'port_address'); expect($uibModalInstance.close).toHaveBeenCalled(); }); it('should dismiss modal if cancel clicked', function() { ctrl = $controller('AssociateFloatingIpModalController'); spyOn($uibModalInstance, 'dismiss'); ctrl.cancel(); expect($uibModalInstance.dismiss).toHaveBeenCalledWith('cancel'); }); it('should not dismiss modal if save fails', function() { ctrl = $controller('AssociateFloatingIpModalController'); ctrl.selected = ctrl.options[0]; associateFail = true; spyOn($uibModalInstance, 'dismiss'); ctrl.save(); expect($uibModalInstance.dismiss).not.toHaveBeenCalled(); expect(ctrl.saving).toBe(false); }); }); })(); ././@PaxHeader0000000000000000000000000000023600000000000010216 xustar00136 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000256015033037474032702 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000024400000000000010215 xustar00142 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000717315033037474032707 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .factory('horizon.dashboard.project.lbaasv2.loadbalancers.actions.associate-ip', modalService); modalService.$inject = [ '$q', '$uibModal', '$route', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.app.core.openstack-service-api.policy', 'horizon.app.core.openstack-service-api.network', 'horizon.framework.util.q.extensions', 'horizon.framework.widgets.toast.service', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc service * @ngname horizon.dashboard.project.lbaasv2.loadbalancers.actions.associate-ip * * @description * Provides the service for the Load Balancer Associate Floating IP action. * * @param $q The angular service for promises. * @param $uibModal The angular bootstrap $uibModal service. * @param $route The angular $route service. * @param basePath The LBaaS v2 module base path. * @param policy The horizon policy service. * @param network The horizon network API service. * @param qExtensions Horizon extensions to the $q service. * @param toastService The horizon toast service. * @param gettext The horizon gettext function for translation. * * @returns The Associate Floating IP modal service. */ function modalService( $q, $uibModal, $route, basePath, policy, network, qExtensions, toastService, gettext ) { var service = { perform: open, allowed: allowed }; return service; //////////// function allowed(item) { return $q.all([ qExtensions.booleanAsPromise(item.floating_ip && !item.floating_ip.ip), // This rule is made up and should therefore always pass. At some point there will // likely be a valid rule similar to this that we will want to use. policy.ifAllowed({ rules: [['neutron', 'loadbalancer_associate_floating_ip']] }) ]); } /** * @ngdoc method * @name open * * @description * Open the modal. * * @param item The row item from the table action. * @returns undefined */ function open(item) { var spec = { backdrop: 'static', controller: 'AssociateFloatingIpModalController as modal', templateUrl: basePath + 'loadbalancers/actions/associate-ip/modal.html', resolve: { loadbalancer: function() { return item; }, floatingIps: function() { return network.getFloatingIps().then(getResponseItems); }, floatingIpPools: function() { return network.getFloatingIpPools().then(getResponseItems); } } }; $uibModal.open(spec).result.then(onModalClose); } function onModalClose() { toastService.add('success', gettext('Associating floating IP with load balancer.')); $route.reload(); } function getResponseItems(response) { return response.data.items; } } })(); ././@PaxHeader0000000000000000000000000000025100000000000010213 xustar00147 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000001003215033037474032673 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Load Balancers Table Associate IP Service', function() { var service, policy, $scope, $route, item, $uibModal, toast; function allowed(item) { spyOn(policy, 'ifAllowed').and.returnValue(true); var promise = service.allowed(item); var allowed; promise.then(function() { allowed = true; }, function() { allowed = false; }); $scope.$apply(); expect(policy.ifAllowed).toHaveBeenCalledWith( {rules: [['neutron', 'loadbalancer_associate_floating_ip']]}); return allowed; } beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(function() { item = { id: '1', name: 'First', floating_ip: {} }; }); beforeEach(module(function($provide) { var fakePromise = function(response) { return { then: function(func) { return func(response); } }; }; $provide.value('$uibModal', { open: function() { return { result: fakePromise() }; } }); $provide.value('horizon.app.core.openstack-service-api.network', { getFloatingIps: function() { return fakePromise({ data: { items: 'foo' } }); }, getFloatingIpPools: function() { return fakePromise({ data: { items: 'bar' } }); } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); toast = $injector.get('horizon.framework.widgets.toast.service'); $scope = $injector.get('$rootScope').$new(); $route = $injector.get('$route'); $uibModal = $injector.get('$uibModal'); service = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.actions.associate-ip'); })); it('should have the "allowed" and "perform" functions', function() { expect(service.allowed).toBeDefined(); expect(service.perform).toBeDefined(); }); it('should check policy to allow the action', function() { expect(allowed(item)).toBe(true); }); it('should not allow action if floating IP already associated', function() { item.floating_ip.ip = 'foo'; expect(allowed(item)).toBe(false); }); it('should open the modal', function() { spyOn($uibModal, 'open').and.callThrough(); service.perform(item); $scope.$apply(); expect($uibModal.open.calls.count()).toBe(1); }); it('should resolve data for passing into the modal', function() { spyOn($uibModal, 'open').and.callThrough(); service.perform(item); $scope.$apply(); var resolve = $uibModal.open.calls.argsFor(0)[0].resolve; expect(resolve).toBeDefined(); expect(resolve.loadbalancer).toBeDefined(); expect(resolve.loadbalancer()).toEqual(item); expect(resolve.floatingIps).toBeDefined(); expect(resolve.floatingIps()).toBe('foo'); expect(resolve.floatingIpPools).toBeDefined(); expect(resolve.floatingIpPools()).toBe('bar'); }); it('should show message and reload page upon closing modal', function() { spyOn(toast, 'add'); spyOn($route, 'reload'); service.perform(item); $scope.$apply(); expect(toast.add).toHaveBeenCalledWith('success', 'Associating floating IP with load balancer.'); expect($route.reload).toHaveBeenCalled(); }); }); })(); ././@PaxHeader0000000000000000000000000000022400000000000010213 xustar00120 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/ 28 mtime=1751924542.4691007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000775000175100017510000000000015033037476032677 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023700000000000010217 xustar00137 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/create.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000441115033037474032677 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .factory('horizon.dashboard.project.lbaasv2.loadbalancers.actions.create', createService); createService.$inject = [ 'horizon.dashboard.project.lbaasv2.loadbalancers.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc service * @ngname horizon.dashboard.project.lbaasv2.loadbalancers.actions.create * * @description * Provides the service for the create load balancer action. * * @param resourceType The loadbalancer resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns Create load balancer action service. */ function createService( resourceType, actionResultService, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'CreateLoadBalancerWizardController', message: gettext('A new load balancer is being created.'), handle: handle, allowed: allowed }); function allowed() { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:loadbalancer:post']] }); } function handle(response) { return actionResultService.getActionResult() .created(resourceType, response.data.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000024400000000000010215 xustar00142 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/create.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000356015033037474032703 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Create Load Balancer Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'loadbalancer1' } }); } } }; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.loadbalancers.actions.create'); })); it('should check policy to allow creating a load balancer', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); expect(service.allowed()).toBe(true); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [[ 'load-balancer', 'os_load-balancer_api:loadbalancer:post' ]] } ); }); it('should handle the action result properly', function() { var result = service.handle({data: {id: 1}}); expect(result.created[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000024200000000000010213 xustar00140 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000314515033037474032702 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .controller('CreateLoadBalancerWizardController', CreateLoadBalancerWizardController); CreateLoadBalancerWizardController.$inject = [ '$scope', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; function CreateLoadBalancerWizardController($scope, model, workflowService, gettext) { var scope = $scope; // Note: We set these attributes on the $scope so that the scope inheritance used all through // the wizard continues to work. Using local var to appease eslint angular/ng_controller_as. scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Create Load Balancer'), 'fa fa-cloud-download', ['loadbalancer', 'listener', 'certificates', 'pool', 'members', 'monitor'] ); scope.model.initialize('loadbalancer'); } })(); ././@PaxHeader0000000000000000000000000000024700000000000010220 xustar00145 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000346415033037474032706 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Create Load Balancer Wizard Controller', function() { var ctrl; var model = { submit: function() { return 'created'; }, initialize: angular.noop }; var workflow = function() { return 'foo'; }; var scope = {}; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow); })); beforeEach(inject(function ($controller) { spyOn(model, 'initialize'); ctrl = $controller('CreateLoadBalancerWizardController', { $scope: scope }); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalled(); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe('foo'); }); it('defines scope.submit', function() { expect(scope.submit).toBeDefined(); expect(scope.submit()).toBe('created'); }); }); })(); ././@PaxHeader0000000000000000000000000000022400000000000010213 xustar00120 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/delete/ 28 mtime=1751924542.4691007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000775000175100017510000000000015033037476032677 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024600000000000010217 xustar00144 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/delete/delete.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000001254015033037474032701 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .factory('horizon.dashboard.project.lbaasv2.loadbalancers.actions.delete', deleteService); deleteService.$inject = [ 'horizon.dashboard.project.lbaasv2.loadbalancers.resourceType', 'horizon.framework.util.actions.action-result.service', '$location', 'horizon.framework.widgets.modal.deleteModalService', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.widgets.toast.service', 'horizon.framework.util.i18n.gettext', 'horizon.framework.util.q.extensions' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.loadbalancers.actions.deleteService * @description * * Brings up the delete load balancers confirmation modal dialog. * On submit, deletes selected load balancers. * On cancel, does nothing. * * @param resourceType The loadbalancer resource type. * @param actionResultService The horizon action result service. * @param $location The angular $location service. * @param deleteModal The horizon delete modal service. * @param api The LBaaS v2 API service. * @param policy The horizon policy service. * @param toast The horizon message service. * @param gettext The horizon gettext function for translation. * @param qExtensions Horizon extensions to the $q service. * * @returns The load balancers delete service. */ function deleteService( resourceType, actionResultService, $location, deleteModal, api, policy, toast, gettext, qExtensions ) { var scope; var context = { }; var service = { perform: perform, allowed: allowed }; return service; ////////////// function perform(items, _scope_) { scope = _scope_; var loadbalancers = angular.isArray(items) ? items : [items]; context.labels = labelize(loadbalancers.length); context.deleteEntity = deleteItem; return qExtensions.allSettled(loadbalancers.map(checkPermission)).then(afterCheck); } function labelize(count) { return { title: ngettext( 'Confirm Delete Load Balancer', 'Confirm Delete Load Balancers', count), message: ngettext( 'You have selected "%s". Deleted load balancer is not recoverable ' + 'and this deletion will delete all of the sub-resources.', 'You have selected "%s". Deleted load balancers are not recoverable ' + 'and this deletion will delete all of the sub-resources.', count), submit: ngettext( 'Delete Load Balancer', 'Delete Load Balancers', count), success: ngettext( 'Deleted Load Balancer: %s.', 'Deleted Load Balancers: %s.', count), error: ngettext( 'Unable to delete Load Balancer: %s.', 'Unable to delete Load Balancers: %s.', count) }; } function deleteResult(deleteModalResult) { // To make the result of this action generically useful, reformat the return // from the deleteModal into a standard form var actionResult = actionResultService.getActionResult(); deleteModalResult.pass.forEach(function markDeleted(item) { actionResult.deleted(resourceType, item.context.id); }); deleteModalResult.fail.forEach(function markFailed(item) { actionResult.failed(resourceType, item.context.id); }); if (actionResult.result.failed.length === 0 && actionResult.result.deleted.length > 0) { var path = 'project/load_balancer'; $location.path(path); } return actionResult.result; } function allowed() { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:loadbalancer:delete']] }); } function canBeDeleted(item) { var status = item.provisioning_status; return qExtensions.booleanAsPromise(status === 'ACTIVE' || status === 'ERROR'); } function checkPermission(item) { return { promise: canBeDeleted(item), context: item }; } function afterCheck(result) { if (result.fail.length > 0) { toast.add('error', getMessage(context.labels.error, result.fail)); } if (result.pass.length > 0) { return deleteModal.open(scope, result.pass.map(getEntity), context).then(deleteResult); } return null; } function deleteItem(id) { return api.deleteLoadBalancer(id, true); } function getMessage(message, entities) { return interpolate(message, [entities.map(getName).join(", ")]); } function getName(result) { return getEntity(result).name; } function getEntity(result) { return result.context; } } })(); ././@PaxHeader0000000000000000000000000000025300000000000010215 xustar00149 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/delete/delete.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000001273415033037474032706 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Load Balancers Table Row Delete Service', function() { var service, policy, modal, lbaasv2Api, $scope, $location, $q, toast, items, path; function allowed(item) { spyOn(policy, 'ifAllowed').and.returnValue(true); var allowed = service.allowed(item); $scope.$apply(); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [[ 'load-balancer', 'os_load-balancer_api:loadbalancer:delete' ]] } ); return allowed; } function makePromise(reject) { var def = $q.defer(); def[reject ? 'reject' : 'resolve'](); return def.promise; } beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(function() { items = [{ id: '1', name: 'First', provisioning_status: 'ACTIVE' }, { id: '2', name: 'Second', provisioning_status: 'ACTIVE' }]; }); beforeEach(module(function($provide) { $provide.value('$uibModal', { open: function() { return { result: makePromise() }; } }); $provide.value('horizon.app.core.openstack-service-api.lbaasv2', { deleteLoadBalancer: function() { return makePromise(); } }); $provide.value('$location', { path: function() { return path; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); lbaasv2Api = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); modal = $injector.get('horizon.framework.widgets.modal.deleteModalService'); $scope = $injector.get('$rootScope').$new(); $location = $injector.get('$location'); $q = $injector.get('$q'); toast = $injector.get('horizon.framework.widgets.toast.service'); service = $injector.get('horizon.dashboard.project.lbaasv2.loadbalancers.actions.delete'); })); it('should have the "allowed" and "perform" functions', function() { expect(service.allowed).toBeDefined(); expect(service.perform).toBeDefined(); }); it('should check policy to allow deleting a load balancer (single)', function() { expect(allowed(items[0])).toBe(true); }); it('should check policy to allow deleting a load balancer (batch)', function() { expect(allowed()).toBe(true); }); it('should open the delete modal', function() { spyOn(modal, 'open').and.callThrough(); service.perform(items[0], $scope); $scope.$apply(); expect(modal.open.calls.count()).toBe(1); var args = modal.open.calls.argsFor(0); expect(args.length).toBe(3); expect(args[0]).toEqual($scope); expect(args[1]).toEqual([jasmine.objectContaining({ id: '1' })]); expect(args[2]).toEqual(jasmine.objectContaining({ labels: jasmine.any(Object), deleteEntity: jasmine.any(Function) })); expect(args[2].labels.title).toBe('Confirm Delete Load Balancer'); }); it('should pass function to modal that deletes load balancers', function() { spyOn(modal, 'open').and.callThrough(); spyOn(lbaasv2Api, 'deleteLoadBalancer').and.callThrough(); service.perform(items[0], $scope); $scope.$apply(); expect(lbaasv2Api.deleteLoadBalancer.calls.count()).toBe(1); expect(lbaasv2Api.deleteLoadBalancer).toHaveBeenCalledWith('1', true); }); it('should show message if any selected items do not allow for delete (batch)', function() { spyOn(modal, 'open'); spyOn(toast, 'add'); items[0].provisioning_status = 'PENDING_UPDATE'; items[1].provisioning_status = 'PENDING_DELETE'; service.perform(items, $scope); $scope.$apply(); expect(modal.open).not.toHaveBeenCalled(); expect(toast.add).toHaveBeenCalledWith('error', 'Unable to delete Load Balancers: First, Second.'); }); it('should show message if any items fail to be deleted', function() { spyOn(modal, 'open').and.callThrough(); spyOn(lbaasv2Api, 'deleteLoadBalancer').and.returnValue(makePromise(true)); spyOn(toast, 'add'); items.splice(1, 1); service.perform(items, $scope); $scope.$apply(); expect(modal.open).toHaveBeenCalled(); expect(lbaasv2Api.deleteLoadBalancer.calls.count()).toBe(1); expect(toast.add).toHaveBeenCalledWith('error', 'Unable to delete Load Balancer' + ': First.'); }); it('should return to panel after delete if on detail page', function() { path = 'project/load_balancer/1'; spyOn($location, 'path'); spyOn(toast, 'add'); service.perform(items[0], $scope); $scope.$apply(); expect($location.path).toHaveBeenCalledWith('project/load_balancer'); expect(toast.add).toHaveBeenCalledWith('success', 'Deleted Load Balancer: First.'); }); }); })(); ././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00129 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/disassociate-ip/ 28 mtime=1751924542.4701006 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000775000175100017510000000000015033037476032677 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024700000000000010220 xustar00145 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/disassociate-ip/modal.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000655515033037474032712 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .factory( 'horizon.dashboard.project.lbaasv2.loadbalancers.actions.disassociate-ip', modalService); modalService.$inject = [ '$q', '$route', 'horizon.framework.widgets.modal.deleteModalService', 'horizon.app.core.openstack-service-api.network', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.q.extensions', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.loadbalancers.actions.disassociate-ip * * @description * Brings up the disassociate floating IP confirmation modal dialog. * On submit, dsiassociates the floating IP address from the load balancer. * On cancel, does nothing. * * @param $q The angular service for promises. * @param $route The angular $route service. * @param deleteModal The horizon delete modal service. * @param network The horizon network API service. * @param policy The horizon policy service. * @param qExtensions Horizon extensions to the $q service. * @param gettext The horizon gettext function for translation. * * @returns The Disassociate Floating IP modal service. */ function modalService($q, $route, deleteModal, network, policy, qExtensions, gettext) { var loadbalancer; var context = { labels: { title: gettext('Confirm Disassociate Floating IP Address'), /* eslint-disable max-len */ message: gettext('You are about to disassociate the floating IP address from load balancer "%s". Please confirm.'), /* eslint-enable max-len */ submit: gettext('Disassociate'), success: gettext('Disassociated floating IP address from load balancer: %s.'), error: gettext('Unable to disassociate floating IP address from load balancer: %s.') }, deleteEntity: disassociate }; var service = { perform: perform, allowed: allowed }; return service; ////////////// function perform(item) { loadbalancer = item; deleteModal.open({ $emit: actionComplete }, [item], context); } function allowed(item) { return $q.all([ qExtensions.booleanAsPromise(item.floating_ip && !!item.floating_ip.ip), // This rule is made up and should therefore always pass. At some point there will // likely be a valid rule similar to this that we will want to use. policy.ifAllowed({ rules: [['neutron', 'loadbalancer_disassociate_floating_ip']] }) ]); } function disassociate() { return network.disassociateFloatingIp(loadbalancer.floating_ip.id); } function actionComplete() { $route.reload(); } } })(); ././@PaxHeader0000000000000000000000000000025400000000000010216 xustar00150 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/disassociate-ip/modal.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000775615033037474032716 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Load Balancers Table Disassociate IP Service', function() { var service, policy, modal, network, $scope, $route, item; function allowed(item) { spyOn(policy, 'ifAllowed').and.returnValue(true); var promise = service.allowed(item); var allowed; promise.then(function() { allowed = true; }, function() { allowed = false; }); $scope.$apply(); expect(policy.ifAllowed).toHaveBeenCalledWith( {rules: [['neutron', 'loadbalancer_disassociate_floating_ip']]}); return allowed; } beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(function() { item = { id: '1', name: 'First', floating_ip: { id: 'ip1', ip: '1' } }; }); beforeEach(module(function($provide) { var fakePromise = { then: function(func) { func(); } }; $provide.value('$uibModal', { open: function() { return { result: fakePromise }; } }); $provide.value('horizon.app.core.openstack-service-api.network', { disassociateFloatingIp: function() { return fakePromise; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); network = $injector.get('horizon.app.core.openstack-service-api.network'); modal = $injector.get('horizon.framework.widgets.modal.deleteModalService'); $scope = $injector.get('$rootScope').$new(); $route = $injector.get('$route'); service = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.actions.disassociate-ip'); })); it('should have the "allowed" and "perform" functions', function() { expect(service.allowed).toBeDefined(); expect(service.perform).toBeDefined(); }); it('should check policy to allow action', function() { expect(allowed(item)).toBe(true); }); it('should not allow action if floating IP not associated', function() { delete item.floating_ip.ip; expect(allowed(item)).toBe(false); }); it('should open the delete modal', function() { spyOn(modal, 'open'); service.perform(item); $scope.$apply(); expect(modal.open.calls.count()).toBe(1); var args = modal.open.calls.argsFor(0); expect(args.length).toBe(3); expect(args[0]).toEqual({ $emit: jasmine.any(Function) }); expect(args[1]).toEqual([jasmine.objectContaining({ id: '1' })]); expect(args[2]).toEqual(jasmine.objectContaining({ labels: jasmine.any(Object), deleteEntity: jasmine.any(Function) })); expect(args[2].labels.title).toBe('Confirm Disassociate Floating IP Address'); }); it('should pass function to modal that disassociates the IP address', function() { spyOn(modal, 'open').and.callThrough(); spyOn(network, 'disassociateFloatingIp').and.callThrough(); service.perform(item); $scope.$apply(); expect(network.disassociateFloatingIp.calls.count()).toBe(1); expect(network.disassociateFloatingIp).toHaveBeenCalledWith('ip1'); }); it('should reload page after action completes', function() { spyOn($route, 'reload'); service.perform(item); $scope.$apply(); expect($route.reload).toHaveBeenCalled(); }); }); })(); ././@PaxHeader0000000000000000000000000000022200000000000010211 xustar00118 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/ 28 mtime=1751924542.4701006 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000775000175100017510000000000015033037476032677 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023300000000000010213 xustar00133 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/edit.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000463015033037474032702 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .factory('horizon.dashboard.project.lbaasv2.loadbalancers.actions.edit', editService); editService.$inject = [ 'horizon.dashboard.project.lbaasv2.loadbalancers.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.q.extensions', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc service * @ngname horizon.dashboard.project.lbaasv2.loadbalancers.actions.edit * * @description * Provides the service for the edit load balancer action. * * @param resourceType The loadbalancer resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param qExtensions Horizon extensions to the $q service. * @param gettext The horizon gettext function for translation. * * @returns Edit load balancer action service. */ function editService( resourceType, actionResultService, workflowModal, policy, qExtensions, gettext ) { return workflowModal.init({ controller: 'EditLoadBalancerWizardController', message: gettext('The load balancer has been updated.'), handle: handle, allowed: allowed }); /////////////// function allowed() { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:loadbalancer:put']] }); } function handle(response) { return actionResultService.getActionResult() .updated(resourceType, response.config.data.loadbalancer.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000024000000000000010211 xustar00138 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/edit.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000403715033037474032703 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Edit Load Balancer Action Service', function() { var service, scope, policy; function canEdit(item) { spyOn(policy, 'ifAllowed').and.returnValue(true); var allowed = service.allowed(item); scope.$apply(); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [[ 'load-balancer', 'os_load-balancer_api:loadbalancer:put' ]] } ); return allowed; } beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func(); } } }; } }); })); beforeEach(inject(function ($injector) { scope = $injector.get('$rootScope').$new(); policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.loadbalancers.actions.edit'); })); it('should allow editing an load balancer', function() { expect(canEdit({provisioning_status: 'ACTIVE'})).toBe(true); }); it('should handle the action result properly', function() { var result = service.handle({config: {data: {loadbalancer: {id: 1}}}}); expect(result.updated[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000024000000000000010211 xustar00138 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000314515033037474032702 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .controller('EditLoadBalancerWizardController', EditLoadBalancerWizardController); EditLoadBalancerWizardController.$inject = [ '$scope', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; function EditLoadBalancerWizardController($scope, model, workflowService, gettext) { var scope = $scope; // Note: We set these attributes on the $scope so that the scope inheritance used all through // the wizard continues to work. Using local var to appease eslint angular/ng_controller_as. scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService(gettext('Update Load Balancer'), 'fa fa-pencil', ['loadbalancer']); scope.model.initialize('loadbalancer', scope.launchContext.id); } })(); ././@PaxHeader0000000000000000000000000000024500000000000010216 xustar00143 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000664000175100017510000000416015033037474032700 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Edit Load Balancer Wizard Controller', function() { var ctrl, workflowSpy; var model = { submit: function() { return 'updated'; }, initialize: angular.noop }; var workflow = 'foo'; var scope = { launchContext: { id: '1' } }; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { workflowSpy = jasmine.createSpy('workflow').and.returnValue(workflow); $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflowSpy); })); beforeEach(inject(function ($controller) { spyOn(model, 'initialize'); ctrl = $controller('EditLoadBalancerWizardController', { $scope: scope }); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalledWith('loadbalancer', '1'); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe(workflow); }); it('initializes workflow with correct properties', function() { expect(workflowSpy).toHaveBeenCalledWith('Update Load Balancer', 'fa fa-pencil', ['loadbalancer']); }); it('defines scope.submit', function() { expect(scope.submit).toBe(model.submit); expect(scope.submit()).toBe('updated'); }); }); })(); ././@PaxHeader0000000000000000000000000000021500000000000010213 xustar00113 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/ 28 mtime=1751924542.4701006 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000775000175100017510000000000015033037476032666 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023300000000000010213 xustar00133 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/detail.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000664000175100017510000001077315033037474032676 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .controller('LoadBalancerDetailController', LoadBalancerDetailController); LoadBalancerDetailController.$inject = [ '$timeout', 'horizon.dashboard.project.lbaasv2.events', '$scope', 'loadbalancer', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.loadbalancers.resourceType', 'horizon.framework.conf.resource-type-registry.service', 'horizon.framework.widgets.modal-wait-spinner.service', '$q' ]; /** * @ngdoc controller * @name LoadBalancerDetailController * * @description * Controller for the LBaaS v2 load balancers detail page. * * @param $timeout The angular timeout object. * @param events The LBaaS v2 events object. * @param $scope The angular scope object. * @param loadbalancer The loadbalancer object. * @param loadBalancersService The LBaaS v2 load balancers service. * @param resourceType The load balancer resource type. * @param typeRegistry The horizon type registry service. * @param spinnerService The horizon modal wait spinner service. * @param $q The angular service for promises. * * @returns undefined */ function LoadBalancerDetailController( $timeout, events, $scope, loadbalancer, loadBalancersService, resourceType, typeRegistry, spinnerService, $q ) { var ctrl = this; ctrl.operatingStatus = loadBalancersService.operatingStatus; ctrl.provisioningStatus = loadBalancersService.provisioningStatus; ctrl.loadbalancer = loadbalancer; ctrl.listFunctionExtraParams = { loadbalancerId: ctrl.loadbalancer.id }; ctrl.resourceType = typeRegistry.getResourceType(resourceType); ctrl.context = {}; ctrl.context.identifier = loadbalancer.id; ctrl.resultHandler = actionResultHandler; $scope.$watch( function() { return ctrl.loadbalancer; }, function() { $timeout.cancel($scope.loadTimeout); $scope.loadTimeout = $timeout(function() { ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); }, loadBalancersService.backoff.duration()); } ); $scope.$on( events.ACTION_DONE, function() { loadBalancersService.backoff.reset(); ctrl.loadbalancer = angular.copy(ctrl.loadbalancer); } ); $scope.$on( '$destroy', function() { $timeout.cancel($scope.loadTimeout); } ); function actionResultHandler(returnValue) { return $q.when(returnValue, actionSuccessHandler); } function loadData(response) { spinnerService.hideModalSpinner(); ctrl.showDetails = true; ctrl.resourceType.initActions(); ctrl.loadbalancer = response.data; ctrl.loadbalancer.floating_ip_address = response.data.floating_ip.ip; ctrl.listFunctionExtraParams = { loadbalancerId: ctrl.loadbalancer.id }; } function actionSuccessHandler(result) { // The action has completed (for whatever "complete" means to that // action. Notice the view doesn't really need to know the semantics of the // particular action because the actions return data in a standard form. // That return includes the id and type of each created, updated, deleted // and failed item. // Currently just refreshes the display each time. if (result) { if (result.failed.length === 0 && result.deleted.length > 0) { // handle a race condition where the resource is already deleted return; } spinnerService.showModalSpinner(gettext('Please Wait')); ctrl.showDetails = false; ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); } } } })(); ././@PaxHeader0000000000000000000000000000024000000000000010211 xustar00138 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/detail.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000664000175100017510000001101515033037474032664 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Load Balancer Detail Controller', function() { var deferred, service, ctrl, scope, $timeout, $q, actionResultService; /////////////////////// beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModal', {}); })); beforeEach(inject(function($controller, $rootScope, _$q_, _$timeout_) { $q = _$q_; deferred = $q.defer(); service = { getResourceType: function() { return { load: function() { return deferred.promise; }, parsePath: function() { return 'my-context'; }, itemName: function() { return 'A name'; }, initActions: angular.noop }; }, getDefaultDetailsTemplateUrl: angular.noop }; actionResultService = { getIdsOfType: function() { return []; } }; $timeout = _$timeout_; scope = $rootScope.$new(); ctrl = $controller('LoadBalancerDetailController', { $scope: scope, loadbalancer: { id: '123', provisioning_status: 'ACTIVE' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); })); it('should create a controller', function() { expect(ctrl).toBeDefined(); expect(ctrl.loadbalancer).toBeDefined(); }); describe('data watchers', function() { var events, loadBalancersService; beforeEach(inject(function($injector) { events = $injector.get('horizon.dashboard.project.lbaasv2.events'); loadBalancersService = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.service' ); })); it('should refresh on provisioning status change', function() { var loadFunctionDeferred = $q.defer(); spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise); ctrl.loadbalancer = { id: '123', provisioning_status: 'PENDING_UPDATE' }; scope.$apply(); $timeout.flush(); expect(ctrl.resourceType.load).toHaveBeenCalled(); spyOn(loadBalancersService.backoff, 'reset').and.callThrough(); scope.$broadcast(events.ACTION_DONE); expect(loadBalancersService.backoff.reset).toHaveBeenCalled(); }); }); describe('resultHandler', function() { it('handles empty results', function() { var result = $q.defer(); result.resolve({failed: [], deleted: []}); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles falsy results', function() { var result = $q.defer(); result.resolve(false); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles matched results', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: []}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data', floating_ip: {}}}); $timeout.flush(); expect(ctrl.showDetails).toBe(true); }); it('handles delete race condition', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data', floating_ip: {}}}); $timeout.flush(); expect(ctrl.showDetails).toBe(undefined); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022200000000000010211 xustar00124 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/detail.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000664000175100017510000000536715033037474032701 0ustar00mylesmyles
././@PaxHeader0000000000000000000000000000022200000000000010211 xustar00124 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/drawer.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000664000175100017510000000051715033037474032671 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000022600000000000010215 xustar00128 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.module.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadb0000664000175100017510000001306615033037474032667 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; /** * @ngdoc overview * @ngname horizon.dashboard.project.lbaasv2.loadbalancers * * @description * Provides the services and widgets required to support and display the project load * balancers v2 panel. */ angular .module('horizon.dashboard.project.lbaasv2.loadbalancers', []) .constant('horizon.dashboard.project.lbaasv2.loadbalancers.resourceType', 'OS::Octavia::LoadBalancer') .run(run); run.$inject = [ 'horizon.framework.conf.resource-type-registry.service', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.loadbalancers.actions.create', 'horizon.dashboard.project.lbaasv2.loadbalancers.actions.edit', 'horizon.dashboard.project.lbaasv2.loadbalancers.actions.associate-ip', 'horizon.dashboard.project.lbaasv2.loadbalancers.actions.disassociate-ip', 'horizon.dashboard.project.lbaasv2.loadbalancers.actions.delete', 'horizon.dashboard.project.lbaasv2.loadbalancers.resourceType' ]; function run( registry, basePath, loadBalancerService, createService, editService, associateIpService, disassociateIpService, deleteService, resourceType ) { var loadBalancerResourceType = registry.getResourceType(resourceType); loadBalancerResourceType .setNames(gettext('Load Balancer'), gettext('Load Balancers')) .setSummaryTemplateUrl(basePath + 'loadbalancers/details/drawer.html') .setProperties(loadBalancerProperties(loadBalancerService)) .setListFunction(loadBalancerService.getLoadBalancersPromise) .setLoadFunction(loadBalancerService.getLoadBalancerPromise) .tableColumns .append({ id: 'name', priority: 1, sortDefault: true, urlFunction: loadBalancerService.getDetailsPath }) .append({ id: 'vip_address', priority: 1 }) .append({ id: 'availability_zone', priority: 1 }) .append({ id: 'operating_status', priority: 1 }) .append({ id: 'provisioning_status', priority: 1 }) .append({ id: 'admin_state_up', priority: 1 }); loadBalancerResourceType.itemActions .append({ id: 'loadBalancerEdit', service: editService, template: { text: gettext('Edit Load Balancer') } }) .append({ id: 'loadBalancerAssociateFloatingIp', service: associateIpService, template: { text: gettext('Associate Floating IP') } }) .append({ id: 'loadBalancerDisassociateFloatingIp', service: disassociateIpService, template: { text: gettext('Disassociate Floating IP') } }) .append({ id: 'loadBalancerDelete', service: deleteService, template: { text: gettext('Delete Load Balancer'), type: 'delete' } }); loadBalancerResourceType.globalActions .append({ id: 'loadBalancerCreate', service: createService, template: { type: 'create', text: gettext('Create Load Balancer') } }); loadBalancerResourceType.batchActions .append({ id: 'loadBalancerBatchDelete', service: deleteService, template: { text: gettext('Delete Load Balancers'), type: 'delete-selected' } }); } function loadBalancerProperties(loadBalancerService) { return { id: gettext('ID'), name: { label: gettext('Name'), filters: ['noName'] }, description: { label: gettext('Description'), filters: ['noName'] }, provisioning_status: { label: gettext('Provisioning Status'), values: loadBalancerService.provisioningStatus }, operating_status: { label: gettext('Operating Status'), values: loadBalancerService.operatingStatus }, admin_state_up: { label: gettext('Admin State Up'), filters: ['yesno'] }, project_id: gettext('Project ID'), created_at: { label: gettext('Created At'), filters: ['noValue'] }, updated_at: { label: gettext('Updated At'), filters: ['noValue'] }, vip_address: gettext('IP Address'), vip_port_id: gettext('Port ID'), vip_subnet_id: gettext('Subnet ID'), vip_network_id: gettext('Network ID'), listeners: gettext('Listeners'), pools: gettext('Pools'), provider: gettext('Provider'), availability_zone: { label: gettext('Availability Zone'), filters: ['noValue'] }, flavor_id: { label: gettext('Flavor ID'), filters: ['noValue'] }, floating_ip_address: { label: gettext('Floating IP'), filters: ['noValue'] } }; } })(); ././@PaxHeader0000000000000000000000000000023300000000000010213 xustar00133 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.module.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadb0000664000175100017510000000453715033037474032672 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Load Balancers Module', function() { it('should exist', function() { expect(angular.module('horizon.dashboard.project.lbaasv2.loadbalancers')).toBeDefined(); }); }); describe('LBaaS v2 Load Balancers Registry', function () { var registry, resourceType; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function($injector) { resourceType = $injector.get('horizon.dashboard.project.lbaasv2.loadbalancers.resourceType'); registry = $injector.get('horizon.framework.conf.resource-type-registry.service'); })); it('should define resourceType', function () { expect(resourceType).toBeDefined(); }); it('should register item actions', function () { var actions = registry.getResourceType(resourceType).itemActions; expect(actionHasId(actions, 'loadBalancerEdit')).toBe(true); expect(actionHasId(actions, 'loadBalancerAssociateFloatingIp')).toBe(true); expect(actionHasId(actions, 'loadBalancerDisassociateFloatingIp')).toBe(true); expect(actionHasId(actions, 'loadBalancerDelete')).toBe(true); }); it('should register global actions', function () { var actions = registry.getResourceType(resourceType).globalActions; expect(actionHasId(actions, 'loadBalancerCreate')).toBe(true); }); it('should register batch actions', function () { var actions = registry.getResourceType(resourceType).batchActions; expect(actionHasId(actions, 'loadBalancerBatchDelete')).toBe(true); }); function actionHasId(list, value) { return list.filter(matchesId).length === 1; function matchesId(action) { return action.id === value; } } }); })(); ././@PaxHeader0000000000000000000000000000022700000000000010216 xustar00129 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadb0000664000175100017510000002566615033037474032700 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .factory('horizon.dashboard.project.lbaasv2.loadbalancers.service', loadBalancersService); loadBalancersService.$inject = [ '$q', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc service * @name horizon.dashboard.project.lbaasv2.loadbalancers.service * * @description General service for LBaaS v2 load balancers. * * @param $q The angular service for promises. * @param api The LBaaS V2 service API. * @param gettext The horizon gettext function for translation. * * @returns The load balancers service. */ function loadBalancersService($q, api, gettext) { var operatingStatus = { ONLINE: gettext('Online'), DRAINING: gettext('Draining'), OFFLINE: gettext('Offline'), DEGRADED: gettext('Degraded'), ERROR: gettext('Error'), NO_MONITOR: gettext('No Monitor') }; var provisioningStatus = { ACTIVE: gettext('Active'), INACTIVE: gettext('Inactive'), PENDING_CREATE: gettext('Pending Create'), PENDING_UPDATE: gettext('Pending Update'), PENDING_DELETE: gettext('Pending Delete'), ERROR: gettext('Error') }; var loadBalancerAlgorithm = { ROUND_ROBIN: gettext('Round Robin'), LEAST_CONNECTIONS: gettext('Least Connections'), SOURCE_IP: gettext('Source IP') }; var l7policyAction = { REJECT: gettext('Reject'), REDIRECT_TO_URL: gettext('Redirect to URL'), REDIRECT_TO_POOL: gettext('Redirect to Pool') }; var l7ruleType = { HOST_NAME: gettext('Host Name'), PATH: gettext('Path'), FILE_TYPE: gettext('File Type'), HEADER: gettext('Header'), COOKIE: gettext('Cookie') }; var l7ruleCompareType = { REGEX: gettext('Regex'), STARTS_WITH: gettext('Starts With'), ENDS_WITH: gettext('Ends With'), CONTAINS: gettext('Contains'), EQUAL_TO: gettext('Equal To') }; var none = { null: gettext('None') }; var backoff = (function() { var min = 250; var max = 5000; var factor = 2; var attempts = 0; function duration() { var ms = min * Math.pow(factor, attempts++); return Math.min(ms, max) | 0; } function reset() { attempts = 0; } return { duration: duration, reset: reset }; }()); var service = { operatingStatus: operatingStatus, provisioningStatus: provisioningStatus, loadBalancerAlgorithm: loadBalancerAlgorithm, l7policyAction: l7policyAction, l7ruleType: l7ruleType, l7ruleCompareType: l7ruleCompareType, none: none, nullFilter: nullFilter, getLoadBalancersPromise: getLoadBalancersPromise, getLoadBalancerPromise: getLoadBalancerPromise, getDetailsPath: getDetailsPath, getListenersPromise: getListenersPromise, getListenerPromise: getListenerPromise, getListenerDetailsPath: getListenerDetailsPath, getL7PoliciesPromise: getL7PoliciesPromise, getL7PolicyPromise: getL7PolicyPromise, getL7PolicyDetailsPath: getL7PolicyDetailsPath, getL7RulesPromise: getL7RulesPromise, getL7RulePromise: getL7RulePromise, getL7RuleDetailsPath: getL7RuleDetailsPath, getPoolsPromise: getPoolsPromise, getPoolPromise: getPoolPromise, getPoolDetailsPath: getPoolDetailsPath, getMembersPromise: getMembersPromise, getMemberPromise: getMemberPromise, getMemberDetailsPath: getMemberDetailsPath, getHealthMonitorPromise: getHealthMonitorPromise, getHealthMonitorsPromise: getHealthMonitorsPromise, getHealthMonitorDetailsPath: getHealthMonitorDetailsPath, isActionable: isActionable, backoff: backoff }; return service; //////////// function nullFilter(input) { if (none.hasOwnProperty(input)) { return none[input]; } return input; } function getMemberDetailsPath(item) { if (item.listenerId) { return 'project/load_balancer/' + item.loadbalancerId + '/listeners/' + item.listenerId + '/pools/' + item.poolId + '/members/' + item.id; } else { return 'project/load_balancer/' + item.loadbalancerId + '/pools/' + item.poolId + '/members/' + item.id; } } function getMembersPromise(params) { return api.getMembers(params.poolId).then(modifyResponse); function modifyResponse(response) { return {data: {items: response.data.items.map(modifyItem)}}; function modifyItem(item) { item.trackBy = item.id + item.updated_at; item.loadbalancerId = params.loadbalancerId; item.listenerId = params.listenerId; item.poolId = params.poolId; return item; } } } function getMemberPromise(poolId, memberId) { return api.getMember(poolId, memberId); } function getHealthMonitorDetailsPath(item) { if (item.listenerId) { return 'project/load_balancer/' + item.loadbalancerId + '/listeners/' + item.listenerId + '/pools/' + item.poolId + '/healthmonitors/' + item.id; } else { return 'project/load_balancer/' + item.loadbalancerId + '/pools/' + item.poolId + '/healthmonitors/' + item.id; } } function getHealthMonitorsPromise(params) { return api.getHealthMonitors(params.poolId).then(modifyResponse); function modifyResponse(response) { return {data: {items: response.data.items.map(modifyItem)}}; function modifyItem(item) { item.trackBy = item.id + item.updated_at; item.loadbalancerId = params.loadbalancerId; item.listenerId = params.listenerId; item.poolId = params.poolId; return item; } } } function getHealthMonitorPromise(identifier) { return api.getHealthMonitor(identifier); } function getPoolsPromise(params) { return api.getPools(params.loadbalancerId, params.listenerId).then(modifyResponse); function modifyResponse(response) { return {data: {items: response.data.items.map(modifyItem)}}; function modifyItem(item) { item.trackBy = item.id + item.updated_at; item.loadbalancerId = params.loadbalancerId; item.listenerId = params.listenerId; return item; } } } function getPoolPromise(identifier) { return api.getPool(identifier); } function getPoolDetailsPath(item) { if (item.listeners.length > 0) { return 'project/load_balancer/' + item.loadbalancerId + '/listeners/' + item.listeners[0].id + '/pools/' + item.id; } else { return 'project/load_balancer/' + item.loadbalancerId + '/pools/' + item.id; } } function getL7RulesPromise(params) { return api.getL7Rules(params.l7policyId).then(modifyResponse); function modifyResponse(response) { return {data: {items: response.data.items.map(modifyItem)}}; function modifyItem(item) { item.trackBy = item.id + item.updated_at; item.loadbalancerId = params.loadbalancerId; item.listenerId = params.listenerId; item.l7policyId = params.l7policyId; return item; } } } function getL7RulePromise(l7policyId, l7ruleId) { return api.getL7Rule(l7policyId, l7ruleId); } function getL7RuleDetailsPath(item) { return 'project/load_balancer/' + item.loadbalancerId + '/listeners/' + item.listenerId + '/l7policies/' + item.l7policyId + '/l7rules/' + item.id; } function getL7PoliciesPromise(params) { return api.getL7Policies(params.listenerId).then(modifyResponse); function modifyResponse(response) { return {data: {items: response.data.items.map(modifyItem)}}; function modifyItem(item) { item.trackBy = item.id + item.updated_at; item.loadbalancerId = params.loadbalancerId; item.listenerId = params.listenerId; return item; } } } function getL7PolicyPromise(identifier) { return api.getL7Policy(identifier); } function getL7PolicyDetailsPath(item) { return 'project/load_balancer/' + item.loadbalancerId + '/listeners/' + item.listenerId + '/l7policies/' + item.id; } function getListenersPromise(params) { return api.getListeners(params.loadbalancerId).then(modifyResponse); function modifyResponse(response) { return {data: {items: response.data.items.map(modifyItem)}}; function modifyItem(item) { item.trackBy = item.id + item.updated_at; item.loadbalancerId = params.loadbalancerId; return item; } } } function getListenerPromise(identifier) { return api.getListener(identifier); } function getListenerDetailsPath(item) { return 'project/load_balancer/' + item.loadbalancerId + '/listeners/' + item.id; } function getLoadBalancersPromise() { return api.getLoadBalancers(true).then(modifyResponse); function modifyResponse(response) { return {data: {items: response.data.items.map(modifyItem)}}; function modifyItem(item) { item.trackBy = item.id + item.updated_at; item.floating_ip_address = item.floating_ip.ip; return item; } } } function getLoadBalancerPromise(identifier) { return api.getLoadBalancer(identifier, true); } function getDetailsPath(item) { return 'project/load_balancer/' + item.id; } /** * @ngdoc method * @name horizon.dashboard.project.lbaasv2.loadbalancers.service.isActionable * @description Returns a promise that is resolved if the load balancer is in a state that * allows for it or child resources to be updated or deleted. * @param id The load balancer id. * @returns {Promise} */ function isActionable(id) { return api.getLoadBalancer(id).then(function onLoad(response) { if (['ACTIVE', 'ERROR'].indexOf(response.data.provisioning_status) < 0) { return $q.reject(); } return null; }); } } }()); ././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00134 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadb0000664000175100017510000003062015033037474032662 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Load Balancers Service', function() { var service, $q, $scope, api; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function ($injector) { $q = $injector.get('$q'); $scope = $injector.get('$rootScope').$new(); service = $injector.get('horizon.dashboard.project.lbaasv2.loadbalancers.service'); api = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); })); it('should define value mappings', function() { expect(service.operatingStatus).toBeDefined(); expect(service.provisioningStatus).toBeDefined(); }); it('should filter null property', function() { expect(service.nullFilter('null')).toBe(gettext('None')); expect(service.nullFilter('something else')).toBe('something else'); }); it('getDetailsPath creates urls using the item\'s ID', function() { var myItem = {id: '1234'}; expect(service.getDetailsPath(myItem)).toBe('project/load_balancer/1234'); }); it("getLoadBalancersPromise provides a promise", inject(function($timeout) { var deferred = $q.defer(); spyOn(api, 'getLoadBalancers').and.returnValue(deferred.promise); var result = service.getLoadBalancersPromise({}); deferred.resolve({data: {items: [{id: 1, updated_at: 'feb8', floating_ip: {}}]}}); $timeout.flush(); expect(result.$$state.value.data.items[0].id).toBe(1); expect(result.$$state.value.data.items[0].updated_at).toBe('feb8'); expect(result.$$state.value.data.items[0].trackBy).toBe('1feb8'); })); it("getLoadBalancerPromise provides a promise", inject(function() { var deferred = $q.defer(); spyOn(api, 'getLoadBalancer').and.returnValue(deferred.promise); var result = service.getLoadBalancerPromise({}); deferred.resolve({data: {id: 1, updated_at: 'feb8', floating_ip: {}}}); expect(result.$$state.value.data.id).toBe(1); expect(result.$$state.value.data.updated_at).toBe('feb8'); })); it('getListenerDetailsPath creates urls using the item\'s ID', function() { var myItem = {loadbalancerId: '123', id: '456'}; expect(service.getListenerDetailsPath(myItem)) .toBe('project/load_balancer/123/listeners/456'); }); it("getListenersPromise provides a promise", inject(function($timeout) { var deferred = $q.defer(); spyOn(api, 'getListeners').and.returnValue(deferred.promise); var result = service.getListenersPromise({loadbalancerId: 3}); deferred.resolve({data: {items: [{id: 1, updated_at: 'feb8'}]}}); $timeout.flush(); expect(result.$$state.value.data.items[0].id).toBe(1); expect(result.$$state.value.data.items[0].updated_at).toBe('feb8'); expect(result.$$state.value.data.items[0].trackBy).toBe('1feb8'); expect(result.$$state.value.data.items[0].loadbalancerId).toBe(3); })); it("getListenerPromise provides a promise", inject(function() { var deferred = $q.defer(); spyOn(api, 'getListener').and.returnValue(deferred.promise); var result = service.getListenerPromise({loadbalancerId: 3}); deferred.resolve({data: {id: 1, updated_at: 'feb8', floating_ip: {}}}); expect(result.$$state.value.data.id).toBe(1); expect(result.$$state.value.data.updated_at).toBe('feb8'); })); it('getL7PolicyDetailsPath creates urls using the item\'s ID', function() { var myItem = {loadbalancerId: '123', id: '789', listenerId: '456'}; expect(service.getL7PolicyDetailsPath(myItem)) .toBe('project/load_balancer/123/listeners/456/l7policies/789'); }); it("getL7PoliciesPromise provides a promise", inject(function($timeout) { var deferred = $q.defer(); spyOn(api, 'getL7Policies').and.returnValue(deferred.promise); var result = service.getL7PoliciesPromise({listenerId: 3}); deferred.resolve({data: {items: [{id: 1, updated_at: 'feb8'}]}}); $timeout.flush(); expect(result.$$state.value.data.items[0].id).toBe(1); expect(result.$$state.value.data.items[0].updated_at).toBe('feb8'); expect(result.$$state.value.data.items[0].trackBy).toBe('1feb8'); expect(result.$$state.value.data.items[0].listenerId).toBe(3); })); it("getL7PolicyPromise provides a promise", inject(function() { var deferred = $q.defer(); spyOn(api, 'getL7Policy').and.returnValue(deferred.promise); var result = service.getL7PolicyPromise(1); deferred.resolve({data: {id: 1, updated_at: 'feb8'}}); expect(result.$$state.value.data.id).toBe(1); expect(result.$$state.value.data.updated_at).toBe('feb8'); })); it('getL7RuleDetailsPath creates urls using the item\'s ID', function() { var myItem = {loadbalancerId: '1', id: '5', listenerId: '2', l7policyId: '3'}; expect(service.getL7RuleDetailsPath(myItem)) .toBe('project/load_balancer/1/listeners/2/l7policies/3/l7rules/5'); }); it("getL7RulesPromise provides a promise", inject(function($timeout) { var deferred = $q.defer(); spyOn(api, 'getL7Rules').and.returnValue(deferred.promise); var result = service.getL7RulesPromise({listenerId: 3, l7policyId: 5}); deferred.resolve({data: {items: [{id: 1, updated_at: 'feb8'}]}}); $timeout.flush(); expect(result.$$state.value.data.items[0].id).toBe(1); expect(result.$$state.value.data.items[0].updated_at).toBe('feb8'); expect(result.$$state.value.data.items[0].trackBy).toBe('1feb8'); expect(result.$$state.value.data.items[0].listenerId).toBe(3); expect(result.$$state.value.data.items[0].l7policyId).toBe(5); })); it("getL7RulePromise provides a promise", inject(function() { var deferred = $q.defer(); spyOn(api, 'getL7Rule').and.returnValue(deferred.promise); var result = service.getL7RulePromise(2, 1); deferred.resolve({data: {id: 1, updated_at: 'feb8'}}); expect(result.$$state.value.data.id).toBe(1); expect(result.$$state.value.data.updated_at).toBe('feb8'); })); it('getPoolDetailsPath creates urls using the item\'s ID', function() { var myItem = {loadbalancerId: '123', id: '789', listeners: [{id: '456'}]}; expect(service.getPoolDetailsPath(myItem)) .toBe('project/load_balancer/123/listeners/456/pools/789'); myItem = {loadbalancerId: '123', id: '789', listeners: []}; expect(service.getPoolDetailsPath(myItem)) .toBe('project/load_balancer/123/pools/789'); }); it("getPoolsPromise provides a promise", inject(function($timeout) { var deferred = $q.defer(); spyOn(api, 'getPools').and.returnValue(deferred.promise); var result = service.getPoolsPromise({loadbalancerId: 3}); deferred.resolve({data: {items: [{id: 1, updated_at: 'feb8'}]}}); $timeout.flush(); expect(result.$$state.value.data.items[0].id).toBe(1); expect(result.$$state.value.data.items[0].updated_at).toBe('feb8'); expect(result.$$state.value.data.items[0].trackBy).toBe('1feb8'); expect(result.$$state.value.data.items[0].loadbalancerId).toBe(3); })); it("getPoolPromise provides a promise", inject(function() { var deferred = $q.defer(); spyOn(api, 'getPool').and.returnValue(deferred.promise); var result = service.getPoolPromise({loadbalancerId: 3}); deferred.resolve({data: {id: 1, updated_at: 'feb8'}}); expect(result.$$state.value.data.id).toBe(1); expect(result.$$state.value.data.updated_at).toBe('feb8'); })); it('getMemberDetailsPath creates urls using the item\'s ID', function() { var myItem = { loadbalancerId: '1', listenerId: '2', poolId: '3', id: '4' }; expect(service.getMemberDetailsPath(myItem)) .toBe('project/load_balancer/1/listeners/2/pools/3/members/4'); myItem = { loadbalancerId: '1', poolId: '3', id: '4' }; expect(service.getMemberDetailsPath(myItem)) .toBe('project/load_balancer/1/pools/3/members/4'); }); it("getMembersPromise provides a promise", inject(function($timeout) { var deferred = $q.defer(); spyOn(api, 'getMembers').and.returnValue(deferred.promise); var result = service.getMembersPromise({ loadbalancerId: 1, listenerId: 2, poolId: 3 }); deferred.resolve({data: {items: [{id: 4, updated_at: 'feb8'}]}}); $timeout.flush(); expect(result.$$state.value.data.items[0].id).toBe(4); expect(result.$$state.value.data.items[0].updated_at).toBe('feb8'); expect(result.$$state.value.data.items[0].trackBy).toBe('4feb8'); expect(result.$$state.value.data.items[0].loadbalancerId).toBe(1); expect(result.$$state.value.data.items[0].listenerId).toBe(2); expect(result.$$state.value.data.items[0].poolId).toBe(3); })); it("getMemberPromise provides a promise", inject(function() { var deferred = $q.defer(); spyOn(api, 'getMember').and.returnValue(deferred.promise); var result = service.getMemberPromise(2, 1); deferred.resolve({data: {id: 1, updated_at: 'feb8'}}); expect(result.$$state.value.data.id).toBe(1); expect(result.$$state.value.data.updated_at).toBe('feb8'); })); it('getHealthMonitorDetailsPath creates urls using the item\'s ID', function() { var myItem = { loadbalancerId: '1', listenerId: '2', poolId: '3', id: '4' }; expect(service.getHealthMonitorDetailsPath(myItem)) .toBe('project/load_balancer/1/listeners/2/pools/3/healthmonitors/4'); myItem = { loadbalancerId: '1', poolId: '3', id: '4' }; expect(service.getHealthMonitorDetailsPath(myItem)) .toBe('project/load_balancer/1/pools/3/healthmonitors/4'); }); it("getHealthMonitorsPromise provides a promise", inject(function($timeout) { var deferred = $q.defer(); spyOn(api, 'getHealthMonitors').and.returnValue(deferred.promise); var result = service.getHealthMonitorsPromise({ loadbalancerId: 1, listenerId: 2, poolId: 3 }); deferred.resolve({data: {items: [{id: 4, updated_at: 'feb8'}]}}); $timeout.flush(); expect(result.$$state.value.data.items[0].id).toBe(4); expect(result.$$state.value.data.items[0].updated_at).toBe('feb8'); expect(result.$$state.value.data.items[0].trackBy).toBe('4feb8'); expect(result.$$state.value.data.items[0].loadbalancerId).toBe(1); expect(result.$$state.value.data.items[0].listenerId).toBe(2); expect(result.$$state.value.data.items[0].poolId).toBe(3); })); it("getHealthMonitorPromise provides a promise", inject(function() { var deferred = $q.defer(); spyOn(api, 'getHealthMonitor').and.returnValue(deferred.promise); var result = service.getHealthMonitorPromise(1); deferred.resolve({data: {id: 1, updated_at: 'feb8'}}); expect(result.$$state.value.data.id).toBe(1); expect(result.$$state.value.data.updated_at).toBe('feb8'); })); it('should allow checking active status of load balancer', function() { var active = null; var deferred = $q.defer(); spyOn(api, 'getLoadBalancer').and.returnValue(deferred.promise); deferred.resolve({data: { provisioning_status: 'ACTIVE'}}); service.isActionable(0).then(function() { active = true; }); $scope.$apply(); expect(active).toBe(true); }); it('should allow checking transitional status of load balancer', function() { var active = null; var deferred = $q.defer(); spyOn(api, 'getLoadBalancer').and.returnValue(deferred.promise); deferred.resolve({data: { provisioning_status: 'PENDING_UPDATE'}}); service.isActionable(0).then(angular.noop, function() { active = false; }); $scope.$apply(); expect(active).toBe(false); }); }); })(); ././@PaxHeader0000000000000000000000000000022200000000000010211 xustar00124 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel0000664000175100017510000000414115033037474032677 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .controller('PanelController', PanelController); PanelController.$inject = [ '$scope', '$timeout', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.events' ]; /** * @ngdoc controller * @name PanelController * * @description * Controller for the LBaaS v2 load balancers panel. * * @param $scope The angular scope object. * @param $timeout The angular timeout object. * @param loadBalancersService The LBaaS v2 load balancers service. * @param events The LBaaS v2 events object. * @returns undefined */ function PanelController( $scope, $timeout, loadBalancersService, events ) { var ctrl = this; ctrl.listFunctionExtraParams = {}; $scope.$watch( function() { return ctrl.listFunctionExtraParams; }, function() { $timeout.cancel($scope.listTimeout); $scope.listTimeout = $timeout(function () { ctrl.listFunctionExtraParams = angular.copy(ctrl.listFunctionExtraParams); }, loadBalancersService.backoff.duration()); } ); $scope.$on( events.ACTION_DONE, function() { loadBalancersService.backoff.reset(); ctrl.listFunctionExtraParams = angular.copy(ctrl.listFunctionExtraParams); } ); $scope.$on( '$destroy', function() { $timeout.cancel($scope.listTimeout); } ); } })(); ././@PaxHeader0000000000000000000000000000022700000000000010216 xustar00129 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel0000664000175100017510000000372315033037474032704 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Load Balancer Panel Controller', function() { var ctrl, scope, $timeout; /////////////////////// beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModal', {}); })); beforeEach(inject(function($controller, $rootScope, _$timeout_) { $timeout = _$timeout_; scope = $rootScope.$new(); ctrl = $controller('PanelController', { $scope: scope }); })); it('should create a controller', function() { expect(ctrl).toBeDefined(); expect(ctrl.listFunctionExtraParams).toBeDefined(); }); describe('data watchers', function() { var events, loadBalancersService; beforeEach(inject(function($injector) { events = $injector.get('horizon.dashboard.project.lbaasv2.events'); loadBalancersService = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.service' ); })); it('should refresh on provisioning status change', function() { ctrl.listFunctionExtraParams = {}; scope.$apply(); $timeout.flush(); spyOn(loadBalancersService.backoff, 'reset').and.callThrough(); scope.$broadcast(events.ACTION_DONE); expect(loadBalancersService.backoff.reset).toHaveBeenCalled(); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021100000000000010207 xustar00115 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel0000664000175100017510000000104015033037474032672 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4701006 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/0000775000175100017510000000000015033037476030517 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4571009 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/0000775000175100017510000000000015033037476032157 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00114 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/delete/ 28 mtime=1751924542.4701006 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/del0000775000175100017510000000000015033037476032644 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024000000000000010211 xustar00138 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/delete/delete.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/del0000664000175100017510000001071215033037474032645 0ustar00mylesmyles/* * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.members') .factory('horizon.dashboard.project.lbaasv2.members.actions.delete', deleteService); deleteService.$inject = [ 'horizon.dashboard.project.lbaasv2.members.resourceType', 'horizon.framework.util.actions.action-result.service', '$location', 'horizon.framework.widgets.modal.deleteModalService', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.framework.util.i18n.gettext', 'horizon.app.core.openstack-service-api.policy' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.members.actions.deleteService * * @description * Brings up the delete member confirmation modal dialog. * On submit, deletes selected member. * On cancel, does nothing. * * @param resourceType The member resource type. * @param actionResultService The horizon action result service. * @param $location The angular $location service. * @param deleteModal The horizon delete modal service. * @param api The LBaaS v2 API service. * @param gettext The horizon gettext function for translation. * @param policy The horizon policy service. * * @returns The load balancers table delete service. */ function deleteService(resourceType, actionResultService, $location, deleteModal, api, gettext, policy) { var loadbalancerId, listenerId, poolId; var service = { perform: perform, allowed: allowed, deleteResult: deleteResult // exposed just for testing }; return service; ////////////// function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:member:delete']] }); } function perform(items, scope) { var context = { }; var members = angular.isArray(items) ? items : [items]; context.labels = labelize(members.length); context.deleteEntity = deleteItem; members.map(function(item) { loadbalancerId = item.loadbalancerId; listenerId = item.listenerId; poolId = item.poolId; }); return deleteModal.open(scope, members, context).then(deleteResult); } function labelize(count) { return { title: ngettext( 'Confirm Delete Member', 'Confirm Delete Members', count), message: ngettext( 'You have selected "%s". Deleted member is not recoverable.', 'You have selected "%s". Deleted members are not recoverable.', count), submit: ngettext( 'Delete Member', 'Delete Members', count), success: ngettext( 'Deleted Member: %s.', 'Deleted Members: %s.', count), error: ngettext( 'Unable to delete Member: %s.', 'Unable to delete Members: %s.', count) }; } function deleteResult(deleteModalResult) { // To make the result of this action generically useful, reformat the return // from the deleteModal into a standard form var actionResult = actionResultService.getActionResult(); deleteModalResult.pass.forEach(function markDeleted(item) { actionResult.deleted(resourceType, item.context.id); }); deleteModalResult.fail.forEach(function markFailed(item) { actionResult.failed(resourceType, item.context.id); }); if (actionResult.result.failed.length === 0 && actionResult.result.deleted.length > 0) { var path; if (listenerId) { path = 'project/load_balancer/' + loadbalancerId + '/listeners/' + listenerId + '/pools/' + poolId; } else { path = 'project/load_balancer/' + loadbalancerId + '/pools/' + poolId; } $location.path(path); } return actionResult.result; } function deleteItem(id) { return api.deleteMember(poolId, id); } } })(); ././@PaxHeader0000000000000000000000000000024500000000000010216 xustar00143 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/delete/delete.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/del0000664000175100017510000001121415033037474032643 0ustar00mylesmyles/* * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Member Delete Service', function() { beforeEach(module('horizon.app.core')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module('horizon.framework')); var deleteModalService, service, lbaasv2API, policyAPI, $location; beforeEach(inject(function($injector) { service = $injector.get('horizon.dashboard.project.lbaasv2.members.actions.delete'); lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); deleteModalService = $injector.get('horizon.framework.widgets.modal.deleteModalService'); policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy'); $location = $injector.get('$location'); })); describe('perform method', function() { beforeEach(function () { // just need for this to return something that looks like a promise but does nothing spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); }); it('should open the modal with correct label', function () { service.perform({name: 'spam'}); var labels = deleteModalService.open.calls.argsFor(0)[2].labels; expect(deleteModalService.open).toHaveBeenCalled(); angular.forEach(labels, function eachLabel(label) { expect(label.toLowerCase()).toContain('member'); }); }); it('should open the delete modal with correct entities', function () { service.perform([{name: 'one'}, {name: 'two'}]); var entities = deleteModalService.open.calls.argsFor(0)[1]; expect(deleteModalService.open).toHaveBeenCalled(); expect(entities.length).toEqual(2); }); it('should pass in a function that deletes an member', function () { spyOn(lbaasv2API, 'deleteMember').and.callFake(angular.noop); service.perform({poolId: 2, id: 1, name: 'one'}); var contextArg = deleteModalService.open.calls.argsFor(0)[2]; var deleteFunction = contextArg.deleteEntity; deleteFunction(1); expect(lbaasv2API.deleteMember).toHaveBeenCalledWith(2, 1); }); }); it('should handle the action result properly with listener', function() { spyOn($location, 'path'); spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); spyOn(lbaasv2API, 'deleteMember').and.callFake(angular.noop); service.perform({loadbalancerId: 1, listenerId: 2, poolId: 3, id: 1, name: 'one'}); var result = service.deleteResult({ fail: [], pass: [{ context: { id: 1 } }] }); var path = 'project/load_balancer/1/listeners/2/pools/3'; expect($location.path).toHaveBeenCalledWith(path); expect(result.deleted[0].id).toBe(1); result = service.deleteResult({ pass: [], fail: [{ context: { id: 1 } }] }); expect(result.failed[0].id).toBe(1); }); it('should handle the action result properly without listener', function() { spyOn($location, 'path'); spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); spyOn(lbaasv2API, 'deleteMember').and.callFake(angular.noop); service.perform({loadbalancerId: 1, poolId: 3, id: 1, name: 'one'}); var result = service.deleteResult({ fail: [], pass: [{ context: { id: 1 } }] }); var path = 'project/load_balancer/1/pools/3'; expect($location.path).toHaveBeenCalledWith(path); expect(result.deleted[0].id).toBe(1); result = service.deleteResult({ pass: [], fail: [{ context: { id: 1 } }] }); expect(result.failed[0].id).toBe(1); }); describe('allow method', function() { it('should use default policy if batch action', function () { spyOn(policyAPI, 'ifAllowed'); service.allowed(); expect(policyAPI.ifAllowed).toHaveBeenCalled(); }); }); // end of allowed }); // end of delete })(); ././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00119 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/ 28 mtime=1751924542.4701006 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000775000175100017510000000000015033037476032641 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024000000000000010211 xustar00138 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000664000175100017510000000627715033037474032655 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.members') .controller('EditMemberModalController', EditMemberModalController); EditMemberModalController.$inject = [ '$uibModalInstance', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.dashboard.project.lbaasv2.patterns', 'horizon.framework.util.i18n.gettext', // Dependencies injected with resolve by $uibModal.open 'poolId', 'member' ]; /** * @ngdoc controller * @name EditMemberModalController * @description * Controller used by the modal service for editing a pool member. * * @param $uibModalInstance The angular bootstrap $uibModalInstance service. * @param api The LBaaS v2 API service. * @param gettext The horizon gettext function for translation. * @param poolId The pool ID. * @param member The pool member to update. * * @returns The Edit Member modal controller. */ function EditMemberModalController($uibModalInstance, api, basePath, patterns, gettext, poolId, member) { var ctrl = this; ctrl.yesNoOptions = [ { label: gettext('Yes'), value: true }, { label: gettext('No'), value: false } ]; // IP address validation pattern ctrl.ipPattern = [patterns.ipv4, patterns.ipv6].join('|'); ctrl.address = member.address; ctrl.protocol_port = member.protocol_port; ctrl.weight = member.weight; ctrl.monitor_address = member.monitor_address; ctrl.monitor_port = member.monitor_port; ctrl.admin_state_up = member.admin_state_up; ctrl.backup = member.backup; ctrl.name = member.name; ctrl.cancel = cancel; ctrl.save = save; ctrl.saving = false; ctrl.weightError = gettext('The weight must be a number between 0 and 256.'); ctrl.monitorAddressError = gettext('The monitor address must be a valid IP address.'); ctrl.monitorPortError = gettext('The monitor port must be a number between 1 and 65535.'); ctrl.helpUrl = basePath + 'workflow/members/members.help.html'; function save() { ctrl.saving = true; return api.editMember(poolId, member.id, { weight: ctrl.weight, monitor_address: ctrl.monitor_address, monitor_port: ctrl.monitor_port, admin_state_up: ctrl.admin_state_up, backup: ctrl.backup, name: ctrl.name }).then(onSuccess, onFailure); } function cancel() { $uibModalInstance.dismiss('cancel'); } function onSuccess() { $uibModalInstance.close(); } function onFailure() { ctrl.saving = false; } } })(); ././@PaxHeader0000000000000000000000000000024500000000000010216 xustar00143 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000664000175100017510000000735315033037474032651 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Member Edit Controller', function() { var ctrl, api, $controller, $uibModalInstance, $scope, $q; var fail = false; function makePromise(reject) { var def = $q.defer(); def[reject ? 'reject' : 'resolve'](); return def.promise; } beforeEach(module('horizon.framework.util.i18n')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModalInstance', { close: angular.noop, dismiss: angular.noop }); $provide.value('poolId', 'pool1'); $provide.value('member', { id: 'member1', address: '3.3.3.3', protocol_port: '443', weight: 1, monitor_address: '1.1.1.1', monitor_port: 80, admin_state_up: true, backup: false, name: 'member name' }); $provide.value('horizon.app.core.openstack-service-api.lbaasv2', { editMember: function() { return makePromise(fail); } }); })); beforeEach(inject(function ($injector) { api = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); $controller = $injector.get('$controller'); $uibModalInstance = $injector.get('$uibModalInstance'); $scope = $injector.get('$rootScope').$new(); $q = $injector.get('$q'); ctrl = $controller('EditMemberModalController'); })); it('should define controller properties', function() { expect(ctrl.cancel).toBeDefined(); expect(ctrl.save).toBeDefined(); expect(ctrl.saving).toBe(false); expect(ctrl.address).toBeDefined(); expect(ctrl.protocol_port).toBeDefined(); expect(ctrl.weight).toBe(1); expect(ctrl.ipPattern).toBeDefined(); expect(ctrl.helpUrl).toBeDefined(); expect(ctrl.weightError).toBe('The weight must be a number between 0 and 256.'); expect(ctrl.monitorAddressError).toBe('The monitor address must be a valid IP address.'); expect(ctrl.monitorPortError).toBe('The monitor port must be a number between 1 and 65535.'); }); it('should edit member weight, monitor address and port', function() { fail = false; spyOn(api, 'editMember').and.callThrough(); spyOn($uibModalInstance, 'close'); ctrl.save(); $scope.$apply(); expect(ctrl.saving).toBe(true); expect(api.editMember).toHaveBeenCalledWith('pool1', 'member1', { weight: 1, monitor_address: '1.1.1.1', monitor_port: 80, admin_state_up: true, backup: false, name: 'member name' }); expect($uibModalInstance.close).toHaveBeenCalled(); }); it('should dismiss modal if cancel clicked', function() { spyOn($uibModalInstance, 'dismiss'); ctrl.cancel(); expect($uibModalInstance.dismiss).toHaveBeenCalledWith('cancel'); }); it('should not dismiss modal if save fails', function() { fail = true; spyOn($uibModalInstance, 'dismiss'); ctrl.save(); $scope.$apply(); expect($uibModalInstance.dismiss).not.toHaveBeenCalled(); expect(ctrl.saving).toBe(false); }); }); })(); ././@PaxHeader0000000000000000000000000000022700000000000010216 xustar00129 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000664000175100017510000001273615033037474032652 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00135 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000664000175100017510000000652615033037474032652 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.members') .factory('horizon.dashboard.project.lbaasv2.members.actions.edit-member', modalService); modalService.$inject = [ '$rootScope', 'horizon.dashboard.project.lbaasv2.events', 'horizon.dashboard.project.lbaasv2.members.resourceType', 'horizon.framework.util.actions.action-result.service', '$uibModal', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.widgets.toast.service', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc service * @ngname horizon.dashboard.project.lbaasv2.members.actions.edit-member.modal.service * * @description * Provides the service for the pool member Edit Member action. * * @param $rootScope The angular root scope object. * @param events The LBaaS v2 events object. * @param resourceType The member resource type. * @param actionResultService The horizon action result service. * @param $uibModal The angular bootstrap $uibModal service. * @param basePath The LBaaS v2 module base path. * @param policy The horizon policy service. * @param toastService The horizon toast service. * @param gettext The horizon gettext function for translation. * * @returns The Edit Member modal service. */ function modalService( $rootScope, events, resourceType, actionResultService, $uibModal, basePath, policy, toastService, gettext ) { var member; var service = { perform: open, allowed: allowed }; return service; //////////// function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:member:put']] }); } /** * @ngdoc method * @name open * * @description * Open the modal. * * @param item The row item from the table action. * @returns undefined */ function open(item) { member = item; var spec = { backdrop: 'static', controller: 'EditMemberModalController as modal', templateUrl: basePath + 'members/actions/edit-member/modal.html', resolve: { poolId: function() { return item.poolId; }, member: function() { return item; } } }; return $uibModal.open(spec).result.then(onModalClose); } function onModalClose() { toastService.add('success', gettext('Pool member has been updated.')); $rootScope.$broadcast(events.ACTION_DONE); return actionResultService.getActionResult() .updated(resourceType, member.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000024200000000000010213 xustar00140 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000664000175100017510000000651415033037474032647 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Member Edit Service', function() { var service, policy, $scope, $route, $uibModal, toast; var member = { poolId:'pool1', id: 'member1' }; var fakePromise = function(response) { return { then: function(func) { return func(response); } }; }; function allowed(item) { spyOn(policy, 'ifAllowed').and.returnValue(true); var allowed = service.allowed(item); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [[ 'load-balancer', 'os_load-balancer_api:member:put' ]] } ); return allowed; } beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.framework.conf')); beforeEach(module('horizon.framework.widgets')); beforeEach(module('horizon.app.core.openstack-service-api')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModal', { open: function() { return { result: fakePromise({config: {data: {member: {id: 1}}}}) }; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); toast = $injector.get('horizon.framework.widgets.toast.service'); $scope = $injector.get('$rootScope').$new(); $route = $injector.get('$route'); $uibModal = $injector.get('$uibModal'); service = $injector.get( 'horizon.dashboard.project.lbaasv2.members.actions.edit-member'); })); it('should have the "allowed" and "perform" functions', function() { expect(service.allowed).toBeDefined(); expect(service.perform).toBeDefined(); }); it('should check policy to allow the action', function() { expect(allowed(member)).toBe(true); }); it('should open the modal', function() { spyOn($uibModal, 'open').and.callThrough(); service.perform(member); $scope.$apply(); expect($uibModal.open.calls.count()).toBe(1); }); it('should resolve data for passing into the modal', function() { spyOn($uibModal, 'open').and.callThrough(); service.perform(member); $scope.$apply(); var resolve = $uibModal.open.calls.argsFor(0)[0].resolve; expect(resolve).toBeDefined(); expect(resolve.poolId()).toBe('pool1'); expect(resolve.member()).toBe(member); }); it('should show message upon closing modal', function() { spyOn(toast, 'add'); spyOn($route, 'reload'); service.perform(member); expect(toast.add).toHaveBeenCalledWith('success', 'Pool member has been updated.'); }); }); })(); ././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00119 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/ 28 mtime=1751924542.4701006 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000775000175100017510000000000015033037476032670 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000025200000000000010214 xustar00148 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/update-member-list.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000664000175100017510000000447015033037474032675 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.members') .factory('horizon.dashboard.project.lbaasv2.members.actions.update-member-list', updateMemberListService); updateMemberListService.$inject = [ 'horizon.dashboard.project.lbaasv2.members.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.members.actions.updateMemberListService * * @description * Provides the service for updating the list of pool members. * * @param resourceType The member resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns The load balancers members update member list service. */ function updateMemberListService( resourceType, actionResultService, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'UpdateMemberListWizardController', message: gettext('The pool members have been updated.'), handle: handle, allowed: allowed }); function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:pool:put']] }); } function handle(response) { return actionResultService.getActionResult() .created(resourceType, response.data.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000025700000000000010221 xustar00153 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/update-member-list.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000664000175100017510000000356315033037474032677 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Update Member List Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'listener1' } }); } } }; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get( 'horizon.dashboard.project.lbaasv2.members.actions.update-member-list' ); })); it('should check policy to allow updating member list', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); expect(service.allowed()).toBe(true); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [[ 'load-balancer', 'os_load-balancer_api:pool:put' ]] } ); }); it('should handle the action result properly', function() { var result = service.handle({data: {id: 1}}); expect(result.created[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000024100000000000010212 xustar00139 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000664000175100017510000000275615033037474032702 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.members') .controller('UpdateMemberListWizardController', UpdateMemberListWizardController); UpdateMemberListWizardController.$inject = [ '$scope', '$routeParams', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; function UpdateMemberListWizardController($scope, $routeParams, model, workflowService, gettext) { var loadbalancerId = $routeParams.loadbalancerId; var poolId = $routeParams.poolId; var scope = $scope; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Add/Remove Pool Members'), 'fa fa-pencil', ['members'] ); scope.model.initialize('members', false, loadbalancerId, poolId); } })(); ././@PaxHeader0000000000000000000000000000024600000000000010217 xustar00144 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000664000175100017510000000450015033037474032667 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Update Member List Wizard Controller', function() { var ctrl, workflowSpy, scope; var model = { submit: function() { return 'updated'; }, initialize: angular.noop }; var workflow = 'foo'; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { workflowSpy = jasmine.createSpy('workflow').and.returnValue(workflow); $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflowSpy); })); beforeEach(inject(function ($controller, $injector) { scope = $injector.get('$rootScope').$new(); spyOn(model, 'initialize').and.callThrough(); ctrl = $controller('UpdateMemberListWizardController', { $scope: scope, $routeParams: {loadbalancerId: 'loadbalancerId', poolId: 'poolId'}}); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalledWith('members', false, 'loadbalancerId', 'poolId'); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe(workflow); }); it('initializes workflow with correct properties', function() { expect(workflowSpy).toHaveBeenCalledWith('Add/Remove Pool Members', 'fa fa-pencil', ['members']); }); it('defines scope.submit', function() { expect(scope.submit).toBe(model.submit); expect(scope.submit()).toBe('updated'); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4701006 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/0000775000175100017510000000000015033037476032144 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022500000000000010214 xustar00127 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/detail.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/det0000664000175100017510000001161315033037474032643 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.members') .controller('MemberDetailController', MemberDetailController); MemberDetailController.$inject = [ '$timeout', 'horizon.dashboard.project.lbaasv2.events', '$scope', 'loadbalancer', 'listener', 'pool', 'member', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.members.resourceType', 'horizon.framework.conf.resource-type-registry.service', 'horizon.framework.widgets.modal-wait-spinner.service', '$q' ]; /** * @ngdoc controller * @name MemberDetailController * * @description * Controller for the LBaaS v2 member detail page. * * @param $timeout The angular timeout object. * @param events The LBaaS v2 events object. * @param $scope The angular scope object. * @param loadbalancer The loadbalancer object. * @param listener The listener object. * @param pool The pool object. * @param member The member object. * @param loadBalancersService The LBaaS v2 load balancers service. * @param resourceType The member resource type. * @param typeRegistry The horizon resource type registry service. * @param spinnerService The horizon modal wait spinner service. * @param $q The angular service for promises. * * @returns undefined */ function MemberDetailController( $timeout, events, $scope, loadbalancer, listener, pool, member, loadBalancersService, resourceType, typeRegistry, spinnerService, $q ) { var ctrl = this; ctrl.operatingStatus = loadBalancersService.operatingStatus; ctrl.provisioningStatus = loadBalancersService.provisioningStatus; ctrl.loadbalancer = loadbalancer; ctrl.listener = listener; if (!angular.equals({}, ctrl.listener)) { ctrl.withListenerStyle = {}; ctrl.withoutListenerStyle = {display: 'none'}; } else { ctrl.withListenerStyle = {display: 'none'}; ctrl.withoutListenerStyle = {}; } ctrl.pool = pool; ctrl.member = member; ctrl.resourceType = typeRegistry.getResourceType(resourceType); ctrl.context = {}; ctrl.context.memberId = member.id; ctrl.context.poolId = pool.id; ctrl.resultHandler = actionResultHandler; $scope.$watch( function() { return ctrl.member; }, function() { $timeout.cancel($scope.loadTimeout); $scope.loadTimeout = $timeout(function() { ctrl.context.loadPromise = ctrl.resourceType.load( ctrl.context.poolId, ctrl.context.memberId ); ctrl.context.loadPromise.then(loadData); }, loadBalancersService.backoff.duration()); } ); $scope.$on( events.ACTION_DONE, function() { loadBalancersService.backoff.reset(); } ); $scope.$on( '$destroy', function() { $timeout.cancel($scope.loadTimeout); } ); function actionResultHandler(returnValue) { return $q.when(returnValue, actionSuccessHandler); } function loadData(response) { spinnerService.hideModalSpinner(); ctrl.showDetails = true; ctrl.resourceType.initActions(); ctrl.member = response.data; ctrl.member.loadbalancerId = ctrl.loadbalancer.id; ctrl.member.listenerId = ctrl.listener.id; ctrl.member.poolId = ctrl.pool.id; } function actionSuccessHandler(result) { // The action has completed (for whatever "complete" means to that // action. Notice the view doesn't really need to know the semantics of the // particular action because the actions return data in a standard form. // That return includes the id and type of each created, updated, deleted // and failed item. // Currently just refreshes the display each time. if (result) { if (result.failed.length === 0 && result.deleted.length > 0) { // handle a race condition where the resource is already deleted return; } spinnerService.showModalSpinner(gettext('Please Wait')); ctrl.showDetails = false; ctrl.context.loadPromise = ctrl.resourceType.load( ctrl.context.poolId, ctrl.context.memberId ); ctrl.context.loadPromise.then(loadData); } } } })(); ././@PaxHeader0000000000000000000000000000023200000000000010212 xustar00132 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/detail.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/det0000664000175100017510000001227315033037474032646 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Member Detail Controller', function() { var deferred, service, ctrl, scope, $timeout, $q, actionResultService; /////////////////////// beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModal', {}); })); beforeEach(inject(function($controller, $rootScope, _$q_, _$timeout_) { $q = _$q_; deferred = $q.defer(); service = { getResourceType: function() { return { load: function() { return deferred.promise; }, parsePath: function() { return 'my-context'; }, itemName: function() { return 'A name'; }, initActions: angular.noop }; }, getDefaultDetailsTemplateUrl: angular.noop }; actionResultService = { getIdsOfType: function() { return []; } }; $timeout = _$timeout_; scope = $rootScope.$new(); ctrl = $controller('MemberDetailController', { $scope: scope, loadbalancer: { id: '123' }, listener: {}, pool: { id: '123' }, member: { id: '123' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); ctrl = $controller('MemberDetailController', { $scope: scope, loadbalancer: { id: '123' }, listener: { id: '123' }, pool: { id: '123' }, member: { id: '123', provisioning_status: 'ACTIVE' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); })); it('should create a controller', function() { expect(ctrl).toBeDefined(); expect(ctrl.loadbalancer).toBeDefined(); expect(ctrl.listener).toBeDefined(); expect(ctrl.pool).toBeDefined(); expect(ctrl.member).toBeDefined(); }); describe('data watchers', function() { var events, loadBalancersService; beforeEach(inject(function($injector) { events = $injector.get('horizon.dashboard.project.lbaasv2.events'); loadBalancersService = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.service' ); })); it('should refresh on provisioning status change', function() { var loadFunctionDeferred = $q.defer(); spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise); ctrl.member = { id: '123', provisioning_status: 'PENDING_UPDATE' }; scope.$apply(); $timeout.flush(); expect(ctrl.resourceType.load).toHaveBeenCalled(); spyOn(loadBalancersService.backoff, 'reset').and.callThrough(); scope.$broadcast(events.ACTION_DONE); expect(loadBalancersService.backoff.reset).toHaveBeenCalled(); }); }); describe('resultHandler', function() { it('handles empty results', function() { var result = $q.defer(); result.resolve({failed: [], deleted: []}); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles falsy results', function() { var result = $q.defer(); result.resolve(false); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles matched results', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: []}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(true); }); it('handles delete race condition', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(undefined); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00118 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/detail.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/det0000664000175100017510000000554715033037474032654 0ustar00mylesmyles
././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00118 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/drawer.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/dra0000664000175100017510000000045615033037474032640 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/members.module.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/members.mod0000664000175100017510000001136215033037474032653 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; /** * @ngdoc overview * @ngname horizon.dashboard.project.lbaasv2.members * * @description * Provides the services and widgets required to support and display the project members * for the load balancers v2 panel. */ angular .module('horizon.dashboard.project.lbaasv2.members', []) .constant('horizon.dashboard.project.lbaasv2.members.resourceType', 'OS::Octavia::Member') .run(run); run.$inject = [ 'horizon.framework.conf.resource-type-registry.service', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.members.actions.update-member-list', 'horizon.dashboard.project.lbaasv2.members.actions.edit-member', 'horizon.dashboard.project.lbaasv2.members.actions.delete', 'horizon.dashboard.project.lbaasv2.members.resourceType' ]; function run( registry, basePath, loadBalancerService, createService, editService, deleteService, resourceType ) { var memberResourceType = registry.getResourceType(resourceType); memberResourceType .setNames(gettext('Member'), gettext('Members')) .setSummaryTemplateUrl(basePath + 'members/details/drawer.html') .setProperties(memberProperties(loadBalancerService)) .setListFunction(loadBalancerService.getMembersPromise) .setLoadFunction(loadBalancerService.getMemberPromise) .tableColumns .append({ id: 'name', priority: 1, sortDefault: true, urlFunction: loadBalancerService.getMemberDetailsPath }) .append({ id: 'address', priority: 1 }) .append({ id: 'protocol_port', priority: 1 }) .append({ id: 'weight', priority: 1 }) .append({ id: 'backup', priority: 1 }) .append({ id: 'operating_status', priority: 1 }) .append({ id: 'provisioning_status', priority: 1 }) .append({ id: 'admin_state_up', priority: 1 }); memberResourceType.itemActions .append({ id: 'memberEdit', service: editService, template: { text: gettext('Edit Member') } }) .append({ id: 'memberDelete', service: deleteService, template: { text: gettext('Delete Member'), type: 'delete' } }); memberResourceType.globalActions .append({ id: 'memberCreate', service: createService, template: { type: 'create', text: gettext('Add/Remove Members') } }); memberResourceType.batchActions .append({ id: 'memberBatchDelete', service: deleteService, template: { text: gettext('Delete Members'), type: 'delete-selected' } }); } function memberProperties(loadBalancerService) { return { id: gettext('ID'), name: { label: gettext('Name'), filters: ['noName'] }, provisioning_status: { label: gettext('Provisioning Status'), values: loadBalancerService.provisioningStatus }, operating_status: { label: gettext('Operating Status'), values: loadBalancerService.operatingStatus }, admin_state_up: { label: gettext('Admin State Up'), filters: ['yesno'] }, backup: { label: gettext('Backup'), filters: ['yesno'] }, address: gettext('IP Address'), protocol_port: gettext('Port'), weight: gettext('Weight'), subnet_id: gettext('Subnet ID'), project_id: gettext('Project ID'), created_at: { label: gettext('Created At'), filters: ['noValue'] }, updated_at: { label: gettext('Updated At'), filters: ['noValue'] }, monitor_address: { label: gettext('Monitor Address'), filters: ['noValue'] }, monitor_port: { label: gettext('Monitor Port'), filters: ['noValue'] } }; } })(); ././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00121 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/members.module.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/members/members.mod0000664000175100017510000000420615033037474032652 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Members Module', function() { it('should exist', function() { expect(angular.module('horizon.dashboard.project.lbaasv2.members')).toBeDefined(); }); }); describe('LBaaS v2 Members Registry', function () { var registry, resourceType; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function($injector) { resourceType = $injector.get('horizon.dashboard.project.lbaasv2.members.resourceType'); registry = $injector.get('horizon.framework.conf.resource-type-registry.service'); })); it('should define resourceType', function () { expect(resourceType).toBeDefined(); }); it('should register item actions', function () { var actions = registry.getResourceType(resourceType).itemActions; expect(actionHasId(actions, 'memberEdit')).toBe(true); expect(actionHasId(actions, 'memberDelete')).toBe(true); }); it('should register global actions', function () { var actions = registry.getResourceType(resourceType).globalActions; expect(actionHasId(actions, 'memberCreate')).toBe(true); }); it('should register batch actions', function () { var actions = registry.getResourceType(resourceType).batchActions; expect(actionHasId(actions, 'memberBatchDelete')).toBe(true); }); function actionHasId(list, value) { return list.filter(matchesId).length === 1; function matchesId(action) { return action.id === value; } } }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4711008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/0000775000175100017510000000000015033037476030221 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4581008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/0000775000175100017510000000000015033037476031661 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00112 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/ 28 mtime=1751924542.4711008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000775000175100017510000000000015033037476032700 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023600000000000010216 xustar00136 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000664000175100017510000000445415033037474032707 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.pools') .factory('horizon.dashboard.project.lbaasv2.pools.actions.create', createService); createService.$inject = [ 'horizon.dashboard.project.lbaasv2.pools.resourceType', 'horizon.framework.util.actions.action-result.service', '$q', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.pools.actions.createService * * @description * Provides the service for creating a pool resource. * * @param resourceType The pool resource type. * @param actionResultService The horizon action result service. * @param $q The angular service for promises. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns The pool create service. */ function createService( resourceType, actionResultService, $q, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'CreatePoolWizardController', message: gettext('A new pool is being created.'), handle: handle, allowed: allowed }); ////////////// function allowed() { return $q.all([ policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:pool:post']] }) ]); } function handle(response) { return actionResultService.getActionResult() .created(resourceType, response.data.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000024300000000000010214 xustar00141 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000664000175100017510000000371315033037474032704 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Create Pool Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'listener1' } }); } } }; } }); $provide.value('$routeParams', {}); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.pools.actions.create'); })); it('should not allow creating a pool if listenerId is not present', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); var allowed = service.allowed(); permissionShouldFail(allowed); }); it('should handle the action result properly', function() { var result = service.handle({data: {id: 1}}); expect(result.created[0].id).toBe(1); }); function permissionShouldFail(permissions) { permissions.then( function() { expect(false).toBe(true); }, function() { expect(true).toBe(true); }); } }); })(); ././@PaxHeader0000000000000000000000000000023200000000000010212 xustar00132 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000664000175100017510000000307515033037474032705 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.pools') .controller('CreatePoolWizardController', CreatePoolWizardController); CreatePoolWizardController.$inject = [ '$scope', '$routeParams', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; function CreatePoolWizardController($scope, $routeParams, model, workflowService, gettext) { var loadbalancerId = $routeParams.loadbalancerId; var listenerId = $routeParams.listenerId; var scope = $scope; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Create Pool'), 'fa fa-cloud-download', ['pool', 'members', 'monitor'] ); if (!listenerId) { listenerId = null; } scope.model.initialize('pool', false, loadbalancerId, listenerId); } })(); ././@PaxHeader0000000000000000000000000000023700000000000010217 xustar00137 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000664000175100017510000000412515033037474032702 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Create Pool Wizard Controller', function() { var ctrl; var model = { submit: function() { return 'created'; }, initialize: angular.noop }; var workflow = function() { return 'foo'; }; var scope = { launchContext: {id: '1234'} }; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflow); })); beforeEach(inject(function ($controller) { spyOn(model, 'initialize'); ctrl = $controller('CreatePoolWizardController', { $scope: scope }); ctrl = $controller( 'CreatePoolWizardController', { $scope: scope, $routeParams: { loadBalancerId: '1', listenerId: '2' } } ); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalled(); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe('foo'); }); it('defines scope.submit', function() { expect(scope.submit).toBeDefined(); expect(scope.submit()).toBe('created'); }); }); })(); ././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00112 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delete/ 28 mtime=1751924542.4711008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delet0000775000175100017510000000000015033037476032677 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023600000000000010216 xustar00136 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delete/delete.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delet0000664000175100017510000001050715033037474032702 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.pools') .factory('horizon.dashboard.project.lbaasv2.pools.actions.delete', deleteService); deleteService.$inject = [ 'horizon.dashboard.project.lbaasv2.pools.resourceType', 'horizon.framework.util.actions.action-result.service', '$location', 'horizon.framework.widgets.modal.deleteModalService', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.framework.util.i18n.gettext', 'horizon.app.core.openstack-service-api.policy' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.pools.actions.deleteService * * @description * Brings up the delete pool confirmation modal dialog. * On submit, deletes selected pool. * On cancel, does nothing. * * @param resourceType The pool resource type. * @param actionResultService The horizon action result service. * @param $location The angular $location service. * @param deleteModal The horizon delete modal service. * @param api The LBaaS v2 API service. * @param gettext The horizon gettext function for translation. * @param policy The horizon policy service. * * @returns The pool delete service. */ function deleteService( resourceType, actionResultService, $location, deleteModal, api, gettext, policy ) { var loadbalancerId, listenerId; var service = { perform: perform, allowed: allowed, deleteResult: deleteResult // exposed just for testing }; return service; ////////////// function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:pool:delete']] }); } function perform(items, scope) { var context = { }; var pools = angular.isArray(items) ? items : [items]; context.labels = labelize(pools.length); context.deleteEntity = deleteItem; pools.map(function(item) { loadbalancerId = item.loadbalancerId; listenerId = item.listenerId; }); return deleteModal.open(scope, pools, context).then(deleteResult); } function labelize(count) { return { title: ngettext( 'Confirm Delete Pool', 'Confirm Delete Pools', count), message: ngettext( 'You have selected "%s". Deleted pool is not recoverable.', 'You have selected "%s". Deleted pools are not recoverable.', count), submit: ngettext( 'Delete Pool', 'Delete Pools', count), success: ngettext( 'Deleted Pool: %s.', 'Deleted Pools: %s.', count), error: ngettext( 'Unable to delete Pool: %s.', 'Unable to delete Pools: %s.', count) }; } function deleteResult(deleteModalResult) { // To make the result of this action generically useful, reformat the return // from the deleteModal into a standard form var actionResult = actionResultService.getActionResult(); deleteModalResult.pass.forEach(function markDeleted(item) { actionResult.deleted(resourceType, item.context.id); }); deleteModalResult.fail.forEach(function markFailed(item) { actionResult.failed(resourceType, item.context.id); }); if (actionResult.result.failed.length === 0 && actionResult.result.deleted.length > 0) { var path; if (listenerId) { path = 'project/load_balancer/' + loadbalancerId + '/listeners/' + listenerId; } else { path = 'project/load_balancer/' + loadbalancerId; } $location.path(path); } return actionResult.result; } function deleteItem(id) { return api.deletePool(id, true); } } })(); ././@PaxHeader0000000000000000000000000000024300000000000010214 xustar00141 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delete/delete.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delet0000664000175100017510000001115115033037474032676 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Pool Delete Service', function() { beforeEach(module('horizon.app.core')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module('horizon.framework')); var deleteModalService, service, lbaasv2API, policyAPI, $location; beforeEach(inject(function($injector) { service = $injector.get('horizon.dashboard.project.lbaasv2.pools.actions.delete'); lbaasv2API = $injector.get('horizon.app.core.openstack-service-api.lbaasv2'); deleteModalService = $injector.get('horizon.framework.widgets.modal.deleteModalService'); policyAPI = $injector.get('horizon.app.core.openstack-service-api.policy'); $location = $injector.get('$location'); })); describe('perform method', function() { beforeEach(function () { // just need for this to return something that looks like a promise but does nothing spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); }); it('should open the modal with correct label', function () { service.perform({name: 'spam'}); var labels = deleteModalService.open.calls.argsFor(0)[2].labels; expect(deleteModalService.open).toHaveBeenCalled(); angular.forEach(labels, function eachLabel(label) { expect(label.toLowerCase()).toContain('pool'); }); }); it('should open the delete modal with correct entities', function () { service.perform([{name: 'one'}, {name: 'two'}]); var entities = deleteModalService.open.calls.argsFor(0)[1]; expect(deleteModalService.open).toHaveBeenCalled(); expect(entities.length).toEqual(2); }); it('should pass in a function that deletes a pool', function () { spyOn(lbaasv2API, 'deletePool').and.callFake(angular.noop); service.perform({id: 1, name: 'one'}); var contextArg = deleteModalService.open.calls.argsFor(0)[2]; var deleteFunction = contextArg.deleteEntity; deleteFunction(1); expect(lbaasv2API.deletePool).toHaveBeenCalledWith(1, true); }); }); it('should handle the action result properly with listener', function() { spyOn($location, 'path'); spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); spyOn(lbaasv2API, 'deletePool').and.callFake(angular.noop); service.perform({loadbalancerId: 1, listenerId: 2, id: 1, name: 'one'}); var result = service.deleteResult({ fail: [], pass: [{ context: { id: 1 } }] }); var path = 'project/load_balancer/1/listeners/2'; expect($location.path).toHaveBeenCalledWith(path); expect(result.deleted[0].id).toBe(1); result = service.deleteResult({ pass: [], fail: [{ context: { id: 1 } }] }); expect(result.failed[0].id).toBe(1); }); it('should handle the action result properly without listener', function() { spyOn($location, 'path'); spyOn(deleteModalService, 'open').and.returnValue({then: angular.noop}); spyOn(lbaasv2API, 'deletePool').and.callFake(angular.noop); service.perform({loadbalancerId: 1, id: 1, name: 'one'}); var result = service.deleteResult({ fail: [], pass: [{ context: { id: 1 } }] }); var path = 'project/load_balancer/1'; expect($location.path).toHaveBeenCalledWith(path); expect(result.deleted[0].id).toBe(1); result = service.deleteResult({ pass: [], fail: [{ context: { id: 1 } }] }); expect(result.failed[0].id).toBe(1); }); describe('allow method', function() { it('should use default policy if batch action', function () { spyOn(policyAPI, 'ifAllowed'); service.allowed(); expect(policyAPI.ifAllowed).toHaveBeenCalled(); }); }); // end of allowed }); // end of delete })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4711008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000775000175100017510000000000015033037476032606 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023200000000000010212 xustar00132 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/edit.action.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000664000175100017510000000427315033037474032614 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.pools') .factory('horizon.dashboard.project.lbaasv2.pools.actions.edit', editService); editService.$inject = [ 'horizon.dashboard.project.lbaasv2.pools.resourceType', 'horizon.framework.util.actions.action-result.service', 'horizon.dashboard.project.lbaasv2.workflow.modal', 'horizon.app.core.openstack-service-api.policy', 'horizon.framework.util.i18n.gettext' ]; /** * @ngDoc factory * @name horizon.dashboard.project.lbaasv2.pools.actions.editService * * @description * Provides the service for editing a pool resource. * * @param resourceType The pool resource type. * @param actionResultService The horizon action result service. * @param workflowModal The LBaaS workflow modal service. * @param policy The horizon policy service. * @param gettext The horizon gettext function for translation. * * @returns The pool edit service. */ function editService( resourceType, actionResultService, workflowModal, policy, gettext ) { return workflowModal.init({ controller: 'EditPoolWizardController', message: gettext('The pool has been updated.'), handle: handle, allowed: allowed }); function allowed(/*item*/) { return policy.ifAllowed({ rules: [['load-balancer', 'os_load-balancer_api:pool:put']] }); } function handle(response) { return actionResultService.getActionResult() .updated(resourceType, response.config.data.pool.id) .result; } } })(); ././@PaxHeader0000000000000000000000000000023700000000000010217 xustar00137 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/edit.action.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000664000175100017510000000352215033037474032610 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Edit Pool Action Service', function() { var policy, service; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$modal', { open: function() { return { result: { then: function(func) { func({ data: { id: 'pool1' } }); } } }; } }); })); beforeEach(inject(function ($injector) { policy = $injector.get('horizon.app.core.openstack-service-api.policy'); service = $injector.get('horizon.dashboard.project.lbaasv2.pools.actions.edit'); })); it('should check policy to allow editing a pool', function() { spyOn(policy, 'ifAllowed').and.returnValue(true); expect(service.allowed()).toBe(true); expect(policy.ifAllowed).toHaveBeenCalledWith( { rules: [[ 'load-balancer', 'os_load-balancer_api:pool:put' ]] } ); }); it('should handle the action result properly', function() { var result = service.handle({config: {data: {pool: {id: 1}}}}); expect(result.updated[0].id).toBe(1); }); }); })(); ././@PaxHeader0000000000000000000000000000023000000000000010210 xustar00130 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/wizard.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000664000175100017510000000364215033037474032613 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.loadbalancers') .controller('EditPoolWizardController', EditPoolWizardController); EditPoolWizardController.$inject = [ '$scope', '$routeParams', '$q', 'horizon.dashboard.project.lbaasv2.workflow.model', 'horizon.dashboard.project.lbaasv2.workflow.workflow', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name EditPoolWizardController * * @description * Controller for the LBaaS v2 edit pool wizard. * * @param $scope The angular scope object. * @param $routeParams The angular $routeParams service. * @param $q The angular service for promises. * @param model The LBaaS V2 workflow model service. * @param workflowService The LBaaS V2 workflow service. * @param gettext The horizon gettext function for translation. * @returns undefined */ function EditPoolWizardController($scope, $routeParams, $q, model, workflowService, gettext) { var scope = $scope; var loadbalancerId = $routeParams.loadbalancerId; scope.model = model; scope.submit = scope.model.submit; scope.workflow = workflowService( gettext('Update Pool'), 'fa fa-pencil', ['pool']); scope.model.initialize('pool', scope.launchContext.id, loadbalancerId); } })(); ././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00135 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/wizard.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000664000175100017510000000472715033037474032620 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('LBaaS v2 Edit Pool Wizard Controller', function() { var ctrl, workflowSpy, $q, scope; var model = { submit: function() { return 'updated'; }, initialize: function() { var defer = $q.defer(); defer.resolve(); return defer.promise; } }; var workflow = { steps: [{id: 'pool'}], append: angular.noop }; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function ($provide) { workflowSpy = jasmine.createSpy('workflow').and.returnValue(workflow); $provide.value('horizon.dashboard.project.lbaasv2.workflow.model', model); $provide.value('horizon.dashboard.project.lbaasv2.workflow.workflow', workflowSpy); })); beforeEach(inject(function ($controller, $injector) { $q = $injector.get('$q'); scope = $injector.get('$rootScope').$new(); scope.launchContext = { id: 'poolId' }; spyOn(model, 'initialize').and.callThrough(); ctrl = $controller('EditPoolWizardController', { $scope: scope, $routeParams: {loadbalancerId: 'loadbalancerId'}}); })); it('defines the controller', function() { expect(ctrl).toBeDefined(); }); it('calls initialize on the given model', function() { expect(model.initialize).toHaveBeenCalledWith('pool', 'poolId', 'loadbalancerId'); }); it('sets scope.workflow to the given workflow', function() { expect(scope.workflow).toBe(workflow); }); it('initializes workflow with correct properties', function() { expect(workflowSpy).toHaveBeenCalledWith('Update Pool', 'fa fa-pencil', ['pool']); }); it('defines scope.submit', function() { expect(scope.submit).toBe(model.submit); expect(scope.submit()).toBe('updated'); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4711008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/0000775000175100017510000000000015033037476031646 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detail.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detai0000664000175100017510000001167615033037474032670 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2.pools') .controller('PoolDetailController', PoolDetailController); PoolDetailController.$inject = [ '$timeout', 'horizon.dashboard.project.lbaasv2.events', '$scope', 'loadbalancer', 'listener', 'pool', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.pools.resourceType', 'horizon.framework.conf.resource-type-registry.service', 'horizon.framework.widgets.modal-wait-spinner.service', '$q' ]; /** * @ngdoc controller * @name PoolDetailController * * @description * Controller for the LBaaS v2 pool detail page. * * @param $timeout The angular timeout object. * @param events The LBaaS v2 events object. * @param $scope The angular scope object. * @param loadbalancer The loadbalancer object. * @param listener The listener object. * @param pool The pool object. * @param loadBalancersService The LBaaS v2 load balancers service. * @param resourceType The load balancer resource type. * @param typeRegistry The horizon type registry service. * @param spinnerService The horizon modal wait spinner service. * @param $q The angular service for promises. * * @returns undefined */ function PoolDetailController( $timeout, events, $scope, loadbalancer, listener, pool, loadBalancersService, resourceType, typeRegistry, spinnerService, $q ) { var ctrl = this; ctrl.operatingStatus = loadBalancersService.operatingStatus; ctrl.provisioningStatus = loadBalancersService.provisioningStatus; ctrl.loadBalancerAlgorithm = loadBalancersService.loadBalancerAlgorithm; ctrl.loadbalancer = loadbalancer; ctrl.listener = listener; if (!angular.equals({}, ctrl.listener)) { ctrl.withListenerStyle = {}; } else { ctrl.withListenerStyle = {display: 'none'}; } ctrl.pool = pool; ctrl.listFunctionExtraParams = { loadbalancerId: ctrl.loadbalancer.id, listenerId: ctrl.listener.id, poolId: ctrl.pool.id }; ctrl.resourceType = typeRegistry.getResourceType(resourceType); ctrl.context = {}; ctrl.context.identifier = pool.id; ctrl.resultHandler = actionResultHandler; $scope.$watch( function() { return ctrl.pool; }, function() { $timeout.cancel($scope.loadTimeout); $scope.loadTimeout = $timeout(function() { ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); }, loadBalancersService.backoff.duration()); } ); $scope.$on( events.ACTION_DONE, function() { loadBalancersService.backoff.reset(); ctrl.pool = angular.copy(ctrl.pool); } ); $scope.$on( '$destroy', function() { $timeout.cancel($scope.loadTimeout); } ); function actionResultHandler(returnValue) { return $q.when(returnValue, actionSuccessHandler); } function loadData(response) { spinnerService.hideModalSpinner(); ctrl.showDetails = true; ctrl.resourceType.initActions(); ctrl.pool = response.data; ctrl.pool.loadbalancerId = ctrl.loadbalancer.id; ctrl.pool.listenerId = ctrl.listener.id; ctrl.listFunctionExtraParams = { loadbalancerId: ctrl.loadbalancer.id, listenerId: ctrl.listener.id, poolId: ctrl.pool.id }; } function actionSuccessHandler(result) { // The action has completed (for whatever "complete" means to that // action. Notice the view doesn't really need to know the semantics of the // particular action because the actions return data in a standard form. // That return includes the id and type of each created, updated, deleted // and failed item. // Currently just refreshes the display each time. if (result) { if (result.failed.length === 0 && result.deleted.length > 0) { // handle a race condition where the resource is already deleted return; } spinnerService.showModalSpinner(gettext('Please Wait')); ctrl.showDetails = false; ctrl.context.loadPromise = ctrl.resourceType.load(ctrl.context.identifier); ctrl.context.loadPromise.then(loadData); } } } })(); ././@PaxHeader0000000000000000000000000000023000000000000010210 xustar00130 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detail.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detai0000664000175100017510000001215315033037474032657 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Pool Detail Controller', function() { var deferred, service, ctrl, scope, $timeout, $q, actionResultService; /////////////////////// beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { $provide.value('$uibModal', {}); })); beforeEach(inject(function($controller, $rootScope, _$q_, _$timeout_) { $q = _$q_; deferred = $q.defer(); service = { getResourceType: function() { return { load: function() { return deferred.promise; }, parsePath: function() { return 'my-context'; }, itemName: function() { return 'A name'; }, initActions: angular.noop }; }, getDefaultDetailsTemplateUrl: angular.noop }; actionResultService = { getIdsOfType: function() { return []; } }; $timeout = _$timeout_; scope = $rootScope.$new(); ctrl = $controller('PoolDetailController', { $scope: scope, loadbalancer: { id: '123' }, listener: {}, pool: { id: '123', provisioning_status: 'ACTIVE' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); ctrl = $controller('PoolDetailController', { $scope: scope, loadbalancer: { id: '123' }, listener: { id: '123' }, pool: { id: '123', provisioning_status: 'ACTIVE' }, 'horizon.framework.conf.resource-type-registry.service': service, 'horizon.framework.util.actions.action-result.service': actionResultService, 'horizon.framework.widgets.modal-wait-spinner.service': { showModalSpinner: angular.noop, hideModalSpinner: angular.noop } }); })); it('should create a controller', function() { expect(ctrl).toBeDefined(); expect(ctrl.loadbalancer).toBeDefined(); expect(ctrl.listener).toBeDefined(); expect(ctrl.pool).toBeDefined(); }); describe('data watchers', function() { var events, loadBalancersService; beforeEach(inject(function($injector) { events = $injector.get('horizon.dashboard.project.lbaasv2.events'); loadBalancersService = $injector.get( 'horizon.dashboard.project.lbaasv2.loadbalancers.service' ); })); it('should refresh on provisioning status change', function() { var loadFunctionDeferred = $q.defer(); spyOn(ctrl.resourceType, 'load').and.returnValue(loadFunctionDeferred.promise); ctrl.pool = { id: '123', provisioning_status: 'PENDING_UPDATE' }; scope.$apply(); $timeout.flush(); expect(ctrl.resourceType.load).toHaveBeenCalled(); spyOn(loadBalancersService.backoff, 'reset').and.callThrough(); scope.$broadcast(events.ACTION_DONE); expect(loadBalancersService.backoff.reset).toHaveBeenCalled(); }); }); describe('resultHandler', function() { it('handles empty results', function() { var result = $q.defer(); result.resolve({failed: [], deleted: []}); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles falsy results', function() { var result = $q.defer(); result.resolve(false); ctrl.resultHandler(result.promise); $timeout.flush(); expect(ctrl.showDetails).not.toBe(true); }); it('handles matched results', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: []}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(true); }); it('handles delete race condition', function() { spyOn(actionResultService, 'getIdsOfType').and.returnValue([1, 2, 3]); var result = $q.defer(); result.resolve({some: 'thing', failed: [], deleted: [{id: 1}]}); ctrl.resultHandler(result.promise); deferred.resolve({data: {some: 'data'}}); $timeout.flush(); expect(ctrl.showDetails).toBe(undefined); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detail.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detai0000664000175100017510000000603115033037474032655 0ustar00mylesmyles
././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/drawer.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/drawe0000664000175100017510000000047415033037474032676 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000020600000000000010213 xustar00112 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.0000664000175100017510000001161215033037474032641 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; /** * @ngdoc overview * @ngname horizon.dashboard.project.lbaasv2.pools * * @description * Provides the services and widgets required to support and display the project pools * for the load balancers v2 panel. */ angular .module('horizon.dashboard.project.lbaasv2.pools', []) .constant('horizon.dashboard.project.lbaasv2.pools.resourceType', 'OS::Octavia::Pool') .run(run); run.$inject = [ 'horizon.framework.conf.resource-type-registry.service', 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.dashboard.project.lbaasv2.loadbalancers.service', 'horizon.dashboard.project.lbaasv2.pools.actions.create', 'horizon.dashboard.project.lbaasv2.pools.actions.edit', 'horizon.dashboard.project.lbaasv2.pools.actions.delete', 'horizon.dashboard.project.lbaasv2.pools.resourceType' ]; function run( registry, basePath, loadBalancerService, createService, editService, deleteService, resourceType ) { var poolResourceType = registry.getResourceType(resourceType); poolResourceType .setNames(gettext('Pool'), gettext('Pools')) .setSummaryTemplateUrl(basePath + 'pools/details/drawer.html') .setProperties(poolProperties(loadBalancerService)) .setListFunction(loadBalancerService.getPoolsPromise) .setLoadFunction(loadBalancerService.getPoolPromise) .tableColumns .append({ id: 'name', priority: 1, sortDefault: true, urlFunction: loadBalancerService.getPoolDetailsPath }) .append({ id: 'protocol', priority: 1 }) .append({ id: 'lb_algorithm', priority: 1 }) .append({ id: 'operating_status', priority: 1 }) .append({ id: 'provisioning_status', priority: 1 }) .append({ id: 'admin_state_up', priority: 1 }); poolResourceType.itemActions .append({ id: 'poolEdit', service: editService, template: { text: gettext('Edit Pool') } }) .append({ id: 'poolDelete', service: deleteService, template: { text: gettext('Delete Pool'), type: 'delete' } }); poolResourceType.globalActions .append({ id: 'poolCreate', service: createService, template: { type: 'create', text: gettext('Create Pool') } }); poolResourceType.batchActions .append({ id: 'poolBatchDelete', service: deleteService, template: { text: gettext('Delete Pools'), type: 'delete-selected' } }); } function poolProperties(loadBalancerService) { return { id: gettext('ID'), name: { label: gettext('Name'), filters: ['noName'] }, description: { label: gettext('Description'), filters: ['noName'] }, provisioning_status: { label: gettext('Provisioning Status'), values: loadBalancerService.provisioningStatus }, operating_status: { label: gettext('Operating Status'), values: loadBalancerService.operatingStatus }, admin_state_up: { label: gettext('Admin State Up'), filters: ['yesno'] }, protocol: gettext('Protocol'), lb_algorithm: { label: gettext('Algorithm'), values: loadBalancerService.loadBalancerAlgorithm }, session_persistence: { label: gettext('Session Persistence'), filters: [ 'json', loadBalancerService.nullFilter ] }, health_monitor_id: { label: gettext('Health Monitor ID'), filters: ['noValue'] }, project_id: gettext('Project ID'), created_at: { label: gettext('Created At'), filters: ['noValue'] }, updated_at: { label: gettext('Updated At'), filters: ['noValue'] }, loadbalancers: gettext('Load Balancers'), listeners: gettext('Listeners'), members: gettext('Members'), tls_enabled: { label: gettext('TLS Enabled'), filters: ['yesno'] }, tls_ciphers: gettext('TLS Cipher String') }; } })(); ././@PaxHeader0000000000000000000000000000021300000000000010211 xustar00117 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.0000664000175100017510000000416615033037474032647 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * Copyright 2017 Walmart. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Pools Module', function() { it('should exist', function() { expect(angular.module('horizon.dashboard.project.lbaasv2.pools')).toBeDefined(); }); }); describe('LBaaS v2 Pools Registry', function () { var registry, resourceType; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function($injector) { resourceType = $injector.get('horizon.dashboard.project.lbaasv2.pools.resourceType'); registry = $injector.get('horizon.framework.conf.resource-type-registry.service'); })); it('should define resourceType', function () { expect(resourceType).toBeDefined(); }); it('should register item actions', function () { var actions = registry.getResourceType(resourceType).itemActions; expect(actionHasId(actions, 'poolEdit')).toBe(true); expect(actionHasId(actions, 'poolDelete')).toBe(true); }); it('should register global actions', function () { var actions = registry.getResourceType(resourceType).globalActions; expect(actionHasId(actions, 'poolCreate')).toBe(true); }); it('should register batch actions', function () { var actions = registry.getResourceType(resourceType).batchActions; expect(actionHasId(actions, 'poolBatchDelete')).toBe(true); }); function actionHasId(list, value) { return list.filter(matchesId).length === 1; function matchesId(action) { return action.id === value; } } }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4581008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/util/0000775000175100017510000000000015033037476030042 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4711008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/0000775000175100017510000000000015033037476032212 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/validate-unique.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/val0000664000175100017510000000377115033037474032725 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; /** * @ngdoc directive * @name horizon.dashboard.project.lbaasv2:validateUnique * @element ng-model * @description * The `validateUnique` directive provides validation * for form input elements to ensure values are unique. * * Validator returns true if model/view value is not in * the array of values specified. * * @restrict A * * @example * ``` * * ``` */ angular .module('horizon.dashboard.project.lbaasv2') .directive('validateUnique', validateUnique); function validateUnique() { var directive = { require: 'ngModel', restrict: 'A', link: link }; return directive; ////////// function link(scope, element, attrs, ctrl) { ctrl.$parsers.push(uniqueValidator); ctrl.$formatters.push(uniqueValidator); attrs.$observe('validateUnique', function () { uniqueValidator(ctrl.$modelValue); }); function uniqueValidator(value) { var values = scope.$eval(attrs.validateUnique); if (angular.isArray(values) && values.length > 0 && values.indexOf(value) > -1) { ctrl.$setValidity('unique', false); } else { ctrl.$setValidity('unique', true); } // Return the value rather than undefined if invalid return value; } } } })(); ././@PaxHeader0000000000000000000000000000023000000000000010210 xustar00130 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/validate-unique.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/val0000664000175100017510000000431415033037474032717 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; describe('validate-unique directive', function () { var $compile, scope, element, port, name; var markup = '
' + '' + '' + '
'; beforeEach(module('horizon.framework.widgets')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function ($injector) { $compile = $injector.get('$compile'); scope = $injector.get('$rootScope').$new(); // generate dom from markup element = $compile(markup)(scope); port = element.children('input[type="number"]'); name = element.children('input[type="string"]'); // setup up initial data scope.ports = [80, 443]; scope.names = ['name1', 'name2']; scope.$apply(); })); it('should be initially empty', function () { expect(port.val()).toEqual(''); expect(name.val()).toEqual(''); expect(port.hasClass('ng-valid')).toBe(true); expect(name.hasClass('ng-valid')).toBe(true); }); it('should be invalid if values are not unique', function () { scope.port = 80; scope.name = 'name1'; scope.$apply(); expect(port.hasClass('ng-valid')).toBe(false); expect(name.hasClass('ng-valid')).toBe(false); }); it('should be valid if values are unique', function () { scope.port = 81; scope.name = 'name3'; scope.$apply(); expect(port.hasClass('ng-valid')).toBe(true); expect(name.hasClass('ng-valid')).toBe(true); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4581008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/0000775000175100017510000000000015033037476030533 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00112 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/ 28 mtime=1751924542.4711008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselec0000775000175100017510000000000015033037476032755 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024000000000000010211 xustar00138 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/filter-select.component.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselec0000664000175100017510000001767415033037474032774 0ustar00mylesmyles/* * 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. */ (function() { 'use strict'; /** * @ngdoc component * @ngname horizon.dashboard.project.lbaasv2:filterSelect * * @param {function} onSelect callback invoked when a selection is made, * receives the selected option as a parameter (required) * @param {object} ng-model the currently selected option. Uses the ng-model * directive to tie into angularjs validations (required) * @param {function} shorthand a function used to create a summarizing text * for an option object passed to it as the first parameter. This text is * displayed in the filter input when an option is selected. (required) * @param {boolean} disabled boolean value controlling the disabled state * of the component (optional, defaults to false) * @param {array} options a collection of objects to be presented for * selection (required) * @param {array} columns array of column defining objects. (required, * see below for details) * @param {boolean} loaded allows the control to be replaced by a loading bar * if required (such as when waiting for data to be loaded) (optional, * defaults to false) * * @description * The filter-select component serves as a more complicated alternative to * the standard select control. * * Options in this component are presented as a customizable table where * each row corresponds to one of the options and allows for the presented * options to be filtered using a text input. * * Columns of the table are defined through the `column` attribute, which * accepts an array of column definition objects. Each object contains two * properties: `label` and `value`. * * * label {string} specifies a text value used as the given columns header * * The displayed text in each column for every option is created by * applying the `value` property of the given column definition to the * option object. It can be of two types with different behaviors: * * * {string} describes the value as a direct property of option objects, * using it as key into the option object * * * {function} defines a callback that is expected to return the desired * text and receives the option as it's parameter * * @example * * $scope.options = [{ * text: "option 1", * number: 1 * }, { * text: "option 2", * number: 2 * }] * $scope.onSelect = function(option) { scope.value = option; }; * $scope.columns = [{ * label: "Column 1", * value: "text" * }, { * label: "Column 2", * value: function(option) { return option['number']; }; * }]; * $scope.shorthand = function(option) { * return option['text'] + " => " + option['number']; * }; * * ``` * * * ``` * * The rendered table would then look as follows: * * | Column 1 | Column 2 | * |----------|----------| * | Option 1 | 1 | * |----------|----------| * | Option 2 | 2 | * * If the first option is selected, the shorthand function is invoked and * the following is displayed in the input box: 'Option1 => 1' * */ angular .module('horizon.dashboard.project.lbaasv2') .component('filterSelect', { templateUrl: getTemplate, controller: filterSelectController, require: { ngModelCtrl: "ngModel" }, bindings: { onSelect: '&', shorthand: '<', columns: '<', options: '<', disabled: '<', loaded: '<', ngModel: '<' } }); filterSelectController.$inject = ['$document', '$scope', '$element']; function filterSelectController($document, $scope, $element) { var ctrl = this; ctrl._scope = $scope; // Used to filter rows ctrl.textFilter = ''; // Model for the filtering text input ctrl.text = ''; // Model for the dropdown ctrl.isOpen = false; // Arrays of text to be displayed ctrl.rows = []; // Array of non-rendered options after filter apply ctrl.filtered_options = []; // Lifecycle methods ctrl.$onInit = function() { $document.on('click', ctrl.externalClick); ctrl.loaded = ctrl._setValue(ctrl.loaded, true); ctrl.disabled = ctrl._setValue(ctrl.disabled, false); }; ctrl.$onDestroy = function() { $document.off('click', ctrl.externalClick); }; ctrl.$onChanges = function(changes) { if (changes.ngModel && ctrl.options) { var i = ctrl.options.indexOf(ctrl.ngModel); if (i > -1) { ctrl.textFilter = ''; ctrl.text = ctrl.shorthand(ctrl.ngModel); } } ctrl._buildRows(); }; // Handles clicking outside of the comopnent ctrl.externalClick = function(event) { if (!$element.find(event.target).length) { ctrl._setOpenExternal(false); } }; // Template handleres ctrl.onTextChange = function() { ctrl.onSelect({ option: null }); ctrl.textFilter = ctrl.text; //ctrl._rebuildRows(); ctrl._buildRows(); }; ctrl.togglePopup = function() { ctrl.isOpen = !ctrl.isOpen; }; ctrl.openPopup = function(event) { event.stopPropagation(); ctrl.isOpen = true; }; ctrl.selectOption = function(index) { var option = ctrl.filtered_options[index]; ctrl.onSelect({ option: option }); ctrl.isOpen = false; }; // Internal/Helper methods ctrl._buildCell = function(column, option) { if (angular.isFunction(column.value)) { return column.value(option); } else { return option[column.value]; } }; ctrl._buildRow = function(option) { var row = []; var valid = false; angular.forEach(ctrl.columns, function(column) { var cell = ctrl._buildCell(column, option); var split = ctrl._splitByFilter(cell); valid = valid || split.wasSplit; row.push(split.values); }); if (valid || !ctrl.textFilter) { return row; } else { return null; } }; ctrl._buildRows = function() { ctrl.filtered_options.length = 0; ctrl.rows.length = 0; angular.forEach(ctrl.options, function(option) { var row = ctrl._buildRow(option); if (row) { ctrl.rows.push(row); ctrl.filtered_options.push(option); } }); }; ctrl._splitByFilter = function(text) { var split = { values: [text, "", ""], wasSplit: false }; var i; if (ctrl.textFilter && (i = text.indexOf(ctrl.textFilter)) > -1) { split.values = [ text.substring(0, i), ctrl.textFilter, text.substring(i + ctrl.textFilter.length) ]; split.wasSplit = true; } return split; }; ctrl._setOpenExternal = function(value) { ctrl.isOpen = value; $scope.$apply(); }; ctrl._isUnset = function(property) { return angular.isUndefined(property) || property === null; }; ctrl._setValue = function(property, defaultValue) { return ctrl._isUnset(property) ? defaultValue : property; }; } getTemplate.$inject = ['horizon.dashboard.project.lbaasv2.basePath']; function getTemplate(basePath) { return basePath + 'widgets/filterselect/filter-select.html'; } })(); ././@PaxHeader0000000000000000000000000000024500000000000010216 xustar00143 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/filter-select.component.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselec0000664000175100017510000002317615033037474032766 0ustar00mylesmyles/* * 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. */ (function() { 'use strict'; describe('Filter-Select', function() { var mockOptions, mockColumns; beforeEach(function() { mockOptions = [{ text: 'Option 1' }, { text: 'Option 2' }]; mockColumns = [{ label: 'Key column', value: 'text' }, { label: 'Function Column', value: function(option) { return option.text + ' extended'; } }]; }); describe('component', function() { var component, ctrl, child, scope, otherElement, filterSelect, element; beforeEach(module('templates')); beforeEach(module('horizon.dashboard.project.lbaasv2', function($provide) { $provide.decorator('filterSelectDirective', function($delegate) { component = $delegate[0]; spyOn(component, 'templateUrl').and.callThrough(); return $delegate; }); } )); beforeEach(inject(function($compile, $rootScope) { scope = $rootScope.$new(); scope.ngModel = null; scope.onSelect = function() {}; scope.shorthand = function(option) { return 'Shorthand: ' + option.text; }; scope.disabled = true; scope.columns = mockColumns; scope.options = mockOptions; var html = ''; var parentElement = angular.element('
'); otherElement = angular.element('
'); filterSelect = angular.element(html); parentElement.append(otherElement); parentElement.append(filterSelect); element = $compile(parentElement)(scope); scope.$apply(); child = element.find('input'); ctrl = filterSelect.controller('filter-select'); spyOn(ctrl, 'onSelect').and.callThrough(); spyOn(ctrl, '_buildRows').and.callThrough(); spyOn(ctrl, 'shorthand').and.callThrough(); spyOn(ctrl, '_setOpenExternal').and.callThrough(); })); it('should load the correct template', function() { expect(component.templateUrl).toHaveBeenCalled(); expect(component.templateUrl()).toBe( '/static/dashboard/project/lbaasv2/' + 'widgets/filterselect/filter-select.html' ); }); it('should react to value change', function() { // Change one way binding for 'value' scope.ngModel = mockOptions[0]; scope.$apply(); expect(ctrl.textFilter).toBe(''); expect(ctrl.text).toBe('Shorthand: Option 1'); expect(ctrl._buildRows).toHaveBeenCalled(); expect(ctrl.shorthand).toHaveBeenCalledWith(mockOptions[0]); }); it('should react to non-option value', function() { // Set one way binding to an impossible value var nonOption = {}; scope.ngModel = nonOption; scope.$apply(); expect(ctrl._buildRows).toHaveBeenCalled(); expect(ctrl.shorthand).not.toHaveBeenCalled(); }); it('should react to non-value change', function() { // Set non-value binding and trigger onChange, make sure value related // changes aren't triggered scope.disabled = false; scope.$apply(); expect(ctrl._buildRows).toHaveBeenCalled(); expect(ctrl.shorthand).not.toHaveBeenCalled(); }); it('should react to outside clicks', function() { var mockChildEvent = { target: child }; ctrl.externalClick(mockChildEvent); expect(ctrl._setOpenExternal).not.toHaveBeenCalled(); var mockOutsideEvent = { target: otherElement }; ctrl.externalClick(mockOutsideEvent); expect(ctrl._setOpenExternal).toHaveBeenCalledWith(false); }); it('should build rows', function() { var expectedRows = [ [['Option 1', '', ''], ['Option 1 extended', '', '']], [['Option 2', '', ''], ['Option 2 extended', '', '']] ]; expect(ctrl.rows).toEqual(expectedRows); // filtered by text ctrl.textFilter = '1'; ctrl._buildRows(); var expectedFiltered = [ [['Option ', '1', ''], ['Option ', '1', ' extended']] ]; expect(ctrl.rows).toEqual(expectedFiltered); }); it('should build cells', function() { // Test that normal string values are used as keys against options var option1text = ctrl._buildCell(ctrl.columns[0], ctrl.options[0]); expect(option1text).toBe('Option 1'); // Test that column value callbacks are called spyOn(ctrl.columns[1], 'value'); ctrl._buildCell(ctrl.columns[1], ctrl.options[0]); expect(ctrl.columns[1].value).toHaveBeenCalledWith(ctrl.options[0]); }); it('should handle text changes', function() { // Test input text changes var mockInput = 'mock input text'; ctrl.text = mockInput; ctrl.onTextChange(); expect(ctrl.textFilter).toEqual(mockInput); expect(ctrl._buildRows).toHaveBeenCalled(); }); it('should select options', function() { ctrl.selectOption(1); expect(ctrl.onSelect).toHaveBeenCalledWith({ option: mockOptions[1] }); expect(ctrl.isOpen).toBe(false); }); it('should select correct option after filter input', function() { var mockInput = '2'; ctrl.text = mockInput; ctrl.onTextChange(); ctrl.selectOption(0); expect(ctrl.onSelect).toHaveBeenCalledWith({ option: mockOptions[1] }); expect(ctrl.filtered_options.length).toBe(1); expect(ctrl.filtered_options[0].text).toContain(mockInput); expect(ctrl.isOpen).toBe(false); }); }); describe('controller', function() { var scope, ctrl; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach( inject( function($rootScope, $componentController) { var events = $._data(document, 'events'); events.click = []; scope = $rootScope.$new(); ctrl = $componentController('filterSelect', { $scope: scope, $element: angular.element('') }); ctrl.$onInit(); spyOn(scope, '$apply'); } ) ); it('should initialize and remove listeners', function() { var events = $._data(document, 'events'); expect(events.click).toBeDefined(); expect(events.click.length).toBe(1); expect(events.click[0].handler).toBe(ctrl.externalClick); ctrl.$onDestroy(); expect(events.click).not.toBeDefined(); }); it('should initialize state', function() { // Initial component state; simply bound values needn't be checked, // angular binding is trusted expect(ctrl.textFilter).toBe(''); expect(ctrl.text).toBe(''); expect(ctrl.isOpen).toBe(false); }); it('should open popup', function() { var mockEvent = { stopPropagation: function() {} }; spyOn(mockEvent, 'stopPropagation'); ctrl.openPopup(mockEvent); expect(mockEvent.stopPropagation).toHaveBeenCalled(); expect(ctrl.isOpen).toBe(true); }); it('should toggle popup', function() { // not much to tests here; utilizes bootstrap dropdown ctrl.togglePopup(); expect(ctrl.isOpen).toBe(true); ctrl.togglePopup(); expect(ctrl.isOpen).toBe(false); }); it('should set open state from outside the digest', function() { ctrl._setOpenExternal(true); expect(ctrl.isOpen).toBe(true); expect(scope.$apply).toHaveBeenCalled(); ctrl._setOpenExternal(false); expect(ctrl.isOpen).toBe(false); expect(scope.$apply).toHaveBeenCalled(); }); it('should check unset values', function() { expect(ctrl._isUnset(null)).toBe(true); expect(ctrl._isUnset(undefined)).toBe(true); expect(ctrl._isUnset('defined_value')).toBe(false); }); it('should set default values correctly', function() { var defaultValue = 'default value'; var realValue = 'input value'; var firstResult = ctrl._setValue(null, defaultValue); expect(firstResult).toBe(defaultValue); var secondResult = ctrl._setValue(realValue, defaultValue); expect(secondResult).toBe(realValue); }); it('should split by filter', function() { ctrl.textFilter = 'matched'; var notSplit = ctrl._splitByFilter('does not match'); expect(notSplit).toEqual({ values:['does not match', '', ''], wasSplit: false }); var split = ctrl._splitByFilter('this matched portion'); expect(split).toEqual({ values: ['this ', 'matched', ' portion'], wasSplit: true }); }); }); }); })(); ././@PaxHeader0000000000000000000000000000023000000000000010210 xustar00130 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/filter-select.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselec0000664000175100017510000000310315033037474032752 0ustar00mylesmyles
{$ column.label $}
{$ column[0] $}{$ column[1] $}{$ column[2] $}
No matching options
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4711008 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/0000775000175100017510000000000015033037476031622 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023000000000000010210 xustar00130 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table-status.directive.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table0000664000175100017510000000312715033037474032635 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .directive('tableStatus', tableStatus); tableStatus.$inject = [ 'horizon.dashboard.project.lbaasv2.basePath' ]; /** * @ngdoc directive * @name horizon.dashboard.project.lbaasv2:tableStatus * @description * The `tableStatus` directive provides a status indicator while loading a table. The table * should have loading and error properties that give the status of the table, and an items * array that holds the items being displayed in the table. The column count can be provided * to fit the status row to an exact number of columns. * @restrict A * * @example * ``` * * ``` */ function tableStatus(basePath) { var directive = { restrict: 'A', templateUrl: basePath + 'widgets/table/table-status.html', scope: { table: '=', columnCount: '=?' } }; return directive; } }()); ././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00135 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table-status.directive.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table0000664000175100017510000000712715033037474032641 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function() { 'use strict'; function digestMarkup(scope, compile, markup) { var element = angular.element(markup); compile(element)(scope); scope.$apply(); return element; } describe('tableStatus directive', function() { var $scope, $compile, markup, table; beforeEach(module('templates')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function($injector) { $compile = $injector.get('$compile'); $scope = $injector.get('$rootScope').$new(); table = { loading: true, error: false, items: [] }; $scope.table = table; markup = ''; })); it('initially shows loading status', function() { var element = digestMarkup($scope, $compile, markup); expect(element).toBeDefined(); expect(element.children().length).toBe(1); expect(element.children().first().hasClass('no-rows-help')).toBe(false); expect(element.find('.progress-bar').hasClass('progress-bar-striped')).toBe(true); expect(element.find('.progress-bar').hasClass('progress-bar-danger')).toBe(false); expect(element.find('.progress-bar > span').length).toBe(1); expect(element.find('.progress-bar > span').hasClass('sr-only')).toBe(true); }); it('indicates error status on error', function() { var element = digestMarkup($scope, $compile, markup); expect(element).toBeDefined(); table.loading = false; table.error = true; $scope.$apply(); expect(element.children().length).toBe(1); expect(element.children().first().hasClass('no-rows-help')).toBe(false); expect(element.find('.progress-bar').hasClass('progress-bar-striped')).toBe(false); expect(element.find('.progress-bar').hasClass('progress-bar-danger')).toBe(true); expect(element.find('.progress-bar > span').length).toBe(1); expect(element.find('.progress-bar > span').hasClass('sr-only')).toBe(false); expect(element.find('.progress-bar > span').text().trim()) .toBe('An error occurred. Please try again later.'); }); it('indicates no rows when there are no rows to display', function() { var element = digestMarkup($scope, $compile, markup); expect(element).toBeDefined(); table.loading = false; table.error = false; $scope.$apply(); expect(element.children().length).toBe(1); expect(element.children().first().hasClass('no-rows-help')).toBe(true); expect(element.find('.progress').length).toBe(0); expect(element.find('span').length).toBe(1); expect(element.find('span').text().trim()).toBe('No items to display.'); }); it('goes away when done loading and there are rows to display', function() { var element = digestMarkup($scope, $compile, markup); expect(element).toBeDefined(); table.loading = false; table.error = false; table.items = ['foo']; $scope.$apply(); expect(element.children().length).toBe(0); }); }); }()); ././@PaxHeader0000000000000000000000000000022000000000000010207 xustar00122 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table-status.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table0000664000175100017510000000123415033037474032632 0ustar00mylesmyles No items to display.
Loading An error occurred. Please try again later.
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4721007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/0000775000175100017510000000000015033037476030737 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000021500000000000010213 xustar00113 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/ 28 mtime=1751924542.4721007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000775000175100017510000000000015033037476032775 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024100000000000010212 xustar00139 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000664000175100017510000000333515033037474033001 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .controller('CertificatesController', CertificatesController); CertificatesController.$inject = [ '$scope', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name CertificatesController * @description * The `CertificatesController` controller provides functions for adding certificates to a * listener. * @param $scope The angular scope object. * @param gettext The horizon gettext function for translation. * @returns undefined */ function CertificatesController($scope, gettext) { var ctrl = this; $('#wizard-side-nav ul li:last').hide(); ctrl.tableData = { available: $scope.model.certificates, allocated: $scope.model.spec.certificates, displayedAvailable: [], displayedAllocated: [] }; ctrl.tableLimits = { maxAllocation: -1 }; ctrl.tableHelp = { availHelpText: '', noneAllocText: gettext('Select certificates from the available certificates below'), noneAvailText: gettext('No available certificates') }; } })(); ././@PaxHeader0000000000000000000000000000024600000000000010217 xustar00144 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000664000175100017510000000372315033037474033002 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function() { 'use strict'; describe('SSL Certificates Step', function() { var certs = [{ id: '1', name: 'foo', expiration: '2015-03-26T21:10:45.417835' }]; beforeEach(module('horizon.framework.util.i18n')); beforeEach(module('horizon.dashboard.project.lbaasv2')); describe('CertificatesController', function() { var ctrl, scope; beforeEach(inject(function($controller) { scope = { model: { spec: { certificates: [] }, certificates: certs } }; ctrl = $controller('CertificatesController', { $scope: scope }); })); it('should define transfer table properties', function() { expect(ctrl.tableData).toBeDefined(); expect(ctrl.tableLimits).toBeDefined(); expect(ctrl.tableHelp).toBeDefined(); }); it('should have available certificates', function() { expect(ctrl.tableData.available).toBeDefined(); expect(ctrl.tableData.available.length).toBe(1); expect(ctrl.tableData.available[0].id).toBe('1'); }); it('should not have allocated members', function() { expect(ctrl.tableData.allocated).toEqual([]); }); it('should allow adding multiple certificates', function() { expect(ctrl.tableLimits.maxAllocation).toBe(-1); }); }); }); })(); ././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00135 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.help.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000664000175100017510000000151415033037474032776 0ustar00mylesmyles

If the listener uses the TERMINATED_HTTPS protocol, then one or more SSL certificates must be selected. The first certificate will be the default.

Use the key-manager service to create any certificate containers before creating the listener. The following documentation provides information on how to create a certificate container:

././@PaxHeader0000000000000000000000000000023000000000000010210 xustar00130 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000664000175100017510000000623415033037474033002 0ustar00mylesmyles

Select one or more SSL certificates for the listener.

Certificate Name Expiration Date
{$ ::trCtrl.helpText.noneAllocText $}
{$ ::row.name $} {$ row.expiration | date | noValue $}
Certificate Name Expiration Date
{$ ::trCtrl.helpText.noneAvailText $}
{$ ::row.name $} {$ row.expiration | date | noValue $}
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4721007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/0000775000175100017510000000000015033037476032501 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023100000000000010211 xustar00131 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l0000664000175100017510000000277415033037474032667 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .controller('L7PolicyDetailsController', L7PolicyDetailsController); L7PolicyDetailsController.$inject = [ 'horizon.dashboard.project.lbaasv2.patterns', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name L7PolicyDetailsController * @description * The `L7PolicyDetailsController` controller provides functions for * configuring the l7policy step of the LBaaS wizard. * @param patterns The LBaaS v2 patterns constant. * @param gettext The horizon gettext function for translation. * @returns undefined */ function L7PolicyDetailsController(patterns, gettext) { var ctrl = this; ctrl.redirectUrlError = gettext('The redirect url must be a valid http or https url.'); ctrl.positionError = gettext('The position must be a number between 1 and 2147483647.'); } })(); ././@PaxHeader0000000000000000000000000000023600000000000010216 xustar00136 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l0000664000175100017510000000221115033037474032651 0ustar00mylesmyles/* * Copyright 2018 Walmart. * * 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. */ (function() { 'use strict'; describe('L7Policy Details Step', function() { beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); describe('L7PolicyDetailsController', function() { var ctrl; beforeEach(inject(function($controller) { ctrl = $controller('L7PolicyDetailsController'); })); it('should define error messages', function() { expect(ctrl.redirectUrlError).toBeDefined(); expect(ctrl.positionError).toBeDefined(); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022500000000000010214 xustar00127 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.help.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l0000664000175100017510000000235715033037474032664 0ustar00mylesmyles

An L7 Policy is a collection of L7 rules associated with a Listener, and which may also have an association to a back-end pool

Action: The L7 policy action. One of REJECT, REDIRECT_TO_URL, or REDIRECT_TO_POOL.

  • REJECT: The request is denied with an appropriate response code, and not forwarded on to any back-end pool.
  • REDIRECT_TO_URL: The request is sent an HTTP redirect to the URL defined in the redirect_url parameter.
  • REDIRECT_TO_POOL: The request is forwarded to the back-end pool associated with the L7 policy.

Position: The position of this policy on the listener. Positions start at 1.

Redirect Pool ID: Requests matching this policy will be redirected to the pool with this ID. Only valid if action is REDIRECT_TO_POOL.

Redirect URL: Requests matching this policy will be redirected to this URL. Only valid if action is REDIRECT_TO_URL.

././@PaxHeader0000000000000000000000000000022000000000000010207 xustar00122 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l0000664000175100017510000000753615033037474032670 0ustar00mylesmyles

Provide the details for the l7 policy.

{$ ::ctrl.redirectUrlError $}
{$ ::ctrl.positionError $}
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4721007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/0000775000175100017510000000000015033037476032151 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022100000000000010210 xustar00123 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.help.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7r0000664000175100017510000000405615033037474032603 0ustar00mylesmyles

An L7 Rule is a single, simple logical test which returns either true or false.

Type: The L7 rule type. One of COOKIE, FILE_TYPE, HEADER, HOST_NAME, or PATH.

  • COOKIE: The rule looks for a cookie named by the key parameter and compares it against the value parameter in the rule.
  • HEADER: The rule looks for a header defined in the key parameter and compares it against the value parameter in the rule.
  • FILE_TYPE: The rule compares the last portion of the URI against the value parameter in the rule. (eg. "txt", "jpg", etc.)
  • PATH: The rule compares the path portion of the HTTP URI against the value parameter in the rule.
  • HOST_NAME: The rule does a comparison between the HTTP/1.1 hostname in the request against the value parameter in the rule.

Compare Type: The comparison type for the L7 rule. One of CONTAINS, ENDS_WITH, EQUAL_TO, REGEX, or STARTS_WITH.

  • REGEX: Perl type regular expression matching.
  • STARTS_WITH: String starts with.
  • ENDS_WITH: String ends with.
  • CONTAINS: String contains.
  • EQUAL_TO: String is equal to.

Key: The key to use for the comparison. For example, the name of the cookie to evaluate.

Value: The value to use for the comparison. For example, the file type to compare.

Invert: When true the logic of the rule is inverted. For example, with invert true, equal to would become not equal to.

././@PaxHeader0000000000000000000000000000021400000000000010212 xustar00118 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7r0000664000175100017510000000720715033037474032604 0ustar00mylesmyles

Provide the details for the l7 rule.

././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4721007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/0000775000175100017510000000000015033037476032564 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000023100000000000010211 xustar00131 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/l0000664000175100017510000000572715033037474032753 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .controller('ListenerDetailsController', ListenerDetailsController); ListenerDetailsController.$inject = [ '$scope', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name ListenerDetailsController * @description * The `ListenerDetailsController` controller provides functions for * configuring the listener details step of the LBaaS wizard. * @param $scope The angular scope object. * @param gettext The horizon gettext function for translation. * @returns undefined */ function ListenerDetailsController($scope, gettext) { var ctrl = this; ctrl.protocolChange = protocolChange; ctrl.createChange = createChange; // Error text for invalid fields ctrl.portNumberError = gettext('The port must be a number between 1 and 65535.'); ctrl.portUniqueError = gettext( 'The port must be unique among all listeners attached to this load balancer.'); ctrl.connectionLimitError = gettext( 'The connection limit must be a number greater than or equal to -1.' ); ctrl.timeoutError = gettext('The timeout must be a number between 0 and 31536000000.'); ctrl.tls_ciphersError = gettext('The cipher string must conform to OpenSSL syntax.'); //////////// function protocolChange(protocol) { var defaultPort = { HTTP: 80, TERMINATED_HTTPS: 443 }[protocol]; while (listenerPortExists(defaultPort)) { defaultPort += 1; } $scope.model.spec.listener.protocol_port = defaultPort; var members = $scope.model.members.concat($scope.model.spec.members); members.forEach(function setMemberPort(member) { member.port = { HTTP: 80, TERMINATED_HTTPS: 80 }[protocol]; }); if (protocol === 'TERMINATED_HTTPS') { $('#wizard-side-nav ul li:last').show(); } else { $('#wizard-side-nav ul li:last').hide(); } } function createChange() { if ($scope.model.context.create_listener === false) { // Disabling listener form disables pool form and monitor form $scope.model.context.create_pool = false; $scope.model.context.create_monitor = false; } } function listenerPortExists(port) { return $scope.model.listenerPorts.some(function(element) { return element === port; }); } } })(); ././@PaxHeader0000000000000000000000000000023600000000000010216 xustar00136 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/l0000664000175100017510000001104315033037474032737 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function() { 'use strict'; describe('Listener Details Step', function() { beforeEach(module('horizon.framework.util.i18n')); beforeEach(module('horizon.dashboard.project.lbaasv2')); describe('ListenerDetailsController', function() { var ctrl, workflow, listener, scope; beforeEach(inject(function($controller) { workflow = { steps: [{ id: 'listener' }], after: angular.noop, remove: angular.noop }; listener = { protocol: null, protocol_port: 80 }; scope = { model: { context: { create_listener: true, create_pool: true, create_monitor: true }, listenerPorts: [80], members: [{port: ''}, {port: ''}], spec: { listener: listener, members: [{port: ''}, {port: ''}] } }, workflow: workflow }; ctrl = $controller('ListenerDetailsController', { $scope: scope }); })); it('should define error messages for invalid fields', function() { expect(ctrl.portNumberError).toBeDefined(); expect(ctrl.portUniqueError).toBeDefined(); }); it('should update port on protocol change to HTTP', function() { ctrl.protocolChange('HTTP'); expect(listener.protocol_port).toBe(81); }); it('should update port on protocol change to TERMINATED_HTTPS', function() { ctrl.protocolChange('TERMINATED_HTTPS'); expect(listener.protocol_port).toBe(443); }); it('should update port on protocol change to TCP', function() { ctrl.protocolChange('TCP'); expect(listener.protocol_port).toBeUndefined(); }); it('should update port on protocol change to UDP', function() { ctrl.protocolChange('UDP'); expect(listener.protocol_port).toBeUndefined(); }); it('should update port on protocol change to SCTP', function() { ctrl.protocolChange('SCTP'); expect(listener.protocol_port).toBeUndefined(); }); it('should update member ports on protocol change to TERMINATED_HTTPS', function() { ctrl.protocolChange('TERMINATED_HTTPS'); scope.model.members.concat(scope.model.spec.members).forEach(function(member) { expect(member.port).toBe(80); }); }); it('should update member ports on protocol change to HTTP', function() { ctrl.protocolChange('HTTP'); scope.model.members.concat(scope.model.spec.members).forEach(function(member) { expect(member.port).toBe(80); }); }); it('should update member ports on protocol change to TCP', function() { ctrl.protocolChange('TCP'); scope.model.members.concat(scope.model.spec.members).forEach(function(member) { expect(member.port).toBeUndefined(); }); }); it('should update member ports on protocol change to UDP', function() { ctrl.protocolChange('UDP'); scope.model.members.concat(scope.model.spec.members).forEach(function(member) { expect(member.port).toBeUndefined(); }); }); it('should update member ports on protocol change to SCTP', function() { ctrl.protocolChange('SCTP'); scope.model.members.concat(scope.model.spec.members).forEach(function(member) { expect(member.port).toBeUndefined(); }); }); it('should update create_pool and create_monitor flags', function() { scope.model.context.create_listener = true; ctrl.createChange(); expect(scope.model.context.create_pool).toBe(true); expect(scope.model.context.create_monitor).toBe(true); scope.model.context.create_listener = false; ctrl.createChange(); expect(scope.model.context.create_pool).toBe(false); expect(scope.model.context.create_monitor).toBe(false); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022500000000000010214 xustar00127 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.help.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/l0000664000175100017510000000472215033037474032745 0ustar00mylesmyles

Each port that listens for traffic on a particular load balancer is configured separately and tied to the load balancer. Multiple listeners can be associated with the same load balancer but each must use a unique port.

Protocol: The protocol for which the front end listens. The TERMINATED_HTTPS protocol is only available if the key-manager service is enabled and you have authority to list certificate containers and secrets.

Port: The port on which the front end listens. Must be an integer from 1 to 65535.

Connection Limit: The maximum number of connections permitted for this listener. Default value is -1 which represents infinite connections.

Default Pool ID: The ID of the pool used by the listener if no L7 policies match.

Insert Headers: Additional headers insertion into HTTP header, only "X-Forwarded-For", "X-Forwarded-Port" and "X-Forwarded-Proto" are supported.

Client Data Timeout: Frontend client inactivity timeout in milliseconds. Default: 50000.

TCP Inspect Timeout: Time, in milliseconds, to wait for additional TCP packets for content inspection. Default: 0.

Member Connect Timeout: Backend member connection timeout in milliseconds. Default: 5000.

Member Data Timeout: Backend member inactivity timeout in milliseconds. Default: 50000.

Allowed Cidrs: A newline separated list of cidrs to be allowed to connect to the listener. An empty list means allow from any.

TLS Cipher String: A string of the allowed ciphers using the OpenSSL syntax. The syntax is a colon separated list of the chiphers, ex. "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256" Note, don't include quotation marks. An empty string sets the default TLS Cipher String configured in Octavia.

././@PaxHeader0000000000000000000000000000022000000000000010207 xustar00122 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/l0000664000175100017510000002711615033037474032747 0ustar00mylesmyles

Provide the details for the listener.

{$ ::ctrl.portNumberError $} {$ ::ctrl.portUniqueError $}
{$ ::ctrl.timeoutError $}
{$ ::ctrl.timeoutError $}
{$ ::ctrl.timeoutError $}
{$ ::ctrl.timeoutError $}
{$ ::ctrl.connectionLimitError $}
{$ ::ctrl.tls_ciphersError $}

Insert Headers

././@PaxHeader0000000000000000000000000000021500000000000010213 xustar00113 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/ 28 mtime=1751924542.4721007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000775000175100017510000000000015033037476032740 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000024100000000000010212 xustar00139 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000664000175100017510000001413415033037474032743 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .controller('LoadBalancerDetailsController', LoadBalancerDetailsController); LoadBalancerDetailsController.$inject = [ 'horizon.dashboard.project.lbaasv2.patterns', 'horizon.framework.util.i18n.gettext', '$scope' ]; /** * @ngdoc controller * @name LoadBalancerDetailsController * @description * The `LoadBalancerDetailsController` controller provides functions for * configuring the load balancers step of the LBaaS wizard. * @param {object} patterns The LBaaS v2 patterns constant. * @param {function} gettext The horizon gettext function for translation. * @param {object} $scope Allows access to the model * @returns {undefined} undefined */ function LoadBalancerDetailsController(patterns, gettext, $scope) { var ctrl = this; // Error text for invalid fields ctrl.ipError = gettext('The IP address is not valid.'); // IP address validation pattern ctrl.ipPattern = [patterns.ipv4, patterns.ipv6].join('|'); // Defines columns for the subnet selection filtered pop-up ctrl.subnetColumns = [{ label: gettext('Network'), value: function(subnet) { var network = $scope.model.networks[subnet.network_id]; return network ? network.name : ''; } }, { label: gettext('Network ID'), value: 'network_id' }, { label: gettext('Subnet'), value: 'name' }, { label: gettext('Subnet ID'), value: 'id' }, { label: gettext('CIDR'), value: 'cidr' }]; ctrl.subnetOptions = []; ctrl.shorthand = function(subnet) { var network = $scope.model.networks[subnet.network_id]; var networkText = network ? network.name : subnet.network_id.substring(0, 10) + '...'; var cidrText = subnet.cidr; var subnetText = subnet.name || subnet.id.substring(0, 10) + '...'; return networkText + ': ' + cidrText + ' (' + subnetText + ')'; }; ctrl.setSubnet = function(option) { if (option) { $scope.model.spec.loadbalancer.vip_subnet_id = option; } else { $scope.model.spec.loadbalancer.vip_subnet_id = null; } }; // Defines columns for the flavor selection filtered pop-up ctrl.flavorColumns = [{ label: gettext('Flavor'), value: 'name' }, { label: gettext('Flavor ID'), value: 'id' }, { label: gettext('Flavor Description'), value: 'description' }]; ctrl.flavorOptions = []; ctrl.flavorShorthand = function(flavor) { var flavorText = flavor.name || flavor.id.substring(0, 10) + '...'; var flavorDescription = flavor.description || ''; return flavorText + ': ' + flavorDescription; }; ctrl.setFlavor = function(option) { if (option) { $scope.model.spec.loadbalancer.flavor_id = option; } else { $scope.model.spec.loadbalancer.flavor_id = null; } }; // Defines columns for the availability_zone selection filtered pop-up ctrl.availabilityZoneColumns = [{ label: gettext('Availability Zone'), value: 'name' }]; ctrl.availabilityZoneOptions = []; ctrl.availabilityZoneShorthand = function(availabilityZone) { return availabilityZone.name; }; ctrl.setAvailabilityZone = function(option) { if (option) { $scope.model.spec.loadbalancer.availability_zone = option; } else { $scope.model.spec.loadbalancer.availability_zone = null; } }; ctrl.dataLoaded = false; ctrl._checkLoaded = function() { if ($scope.model.initialized) { ctrl.buildSubnetOptions(); ctrl.buildFlavorOptions(); ctrl.buildAvailabilityZoneOptions(); ctrl.dataLoaded = true; } }; /* The watchers in this component are a bit of a workaround for the way data is loaded asynchornously in the model service. First data loads are marked by a change of 'model.initialized' from false to true, which should replace the striped loading bar with a functional dropdown. Additional changes to networks and subnets have to be watched even after first loads, however, as those changes need to be applied to the select options */ ctrl.$onInit = function() { $scope.$watchCollection('model.subnets', function() { ctrl._checkLoaded(); }); $scope.$watchCollection('model.networks', function() { ctrl._checkLoaded(); }); $scope.$watchCollection('model.flavors', function() { ctrl._checkLoaded(); }); $scope.$watchCollection('model.availability_zones', function() { ctrl._checkLoaded(); }); $scope.$watch('model.initialized', function() { ctrl._checkLoaded(); }); }; ctrl.buildSubnetOptions = function() { // Subnets are sliced to maintain data immutability ctrl.subnetOptions = $scope.model.subnets.slice(0); }; ctrl.buildFlavorOptions = function() { ctrl.flavorOptions = Object.keys($scope.model.flavors).filter(function(key) { return $scope.model.flavors[key].is_enabled; }).map(function(key) { return $scope.model.flavors[key]; }); }; ctrl.buildAvailabilityZoneOptions = function() { ctrl.availabilityZoneOptions = Object.keys( $scope.model.availability_zones).filter(function(key) { return $scope.model.availability_zones[key].is_enabled; }).map(function(key) { return $scope.model.availability_zones[key]; }); }; } })(); ././@PaxHeader0000000000000000000000000000024600000000000010217 xustar00144 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000664000175100017510000002420515033037474032743 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function() { 'use strict'; describe('Load Balancer Details Step', function() { beforeEach(module('horizon.framework.util.i18n')); beforeEach(module('horizon.dashboard.project.lbaasv2')); describe('LoadBalancerDetailsController', function() { var ctrl, scope, mockSubnets, mockFlavors, mockAvailabilityZones; beforeEach(inject(function($controller, $rootScope) { mockSubnets = [{ id: '7262744a-e1e4-40d7-8833-18193e8de191', network_id: '5d658cef-3402-4474-bb8a-0c1162efd9a9', name: 'subnet_1', cidr: '1.1.1.1/24' }, { id: 'd8056c7e-c810-4ee5-978e-177cb4154d81', network_id: '12345678-0000-0000-0000-000000000000', name: 'subnet_2', cidr: '2.2.2.2/16' }, { id: 'd8056c7e-c810-4ee5-978e-177cb4154d81', network_id: '12345678-0000-0000-0000-000000000000', name: '', cidr: '2.2.2.2/16' }]; mockFlavors = [{ id: '15d990e1-3438-4073-89b8-6e4706f0b176', flavor_profile_id: '79e16118-daba-4255-9d1d-9cc7812e18a1', name: 'flavor_1', description: 'Flavor 1 description', is_enabled: true }, { id: 'b0703ed4-dd30-4dbe-92bb-dccc945365e9', flavor_profile_id: 'ace487e6-9946-4bdc-882e-c889af43fc3b', name: 'flavor_2', is_enabled: true }, { id: '94306089-567a-44ed-ab16-87653adbece3', flavor_profile_id: 'b272d5fb-0021-4002-beb5-db758e59a763', name: '', is_enabled: true }]; mockAvailabilityZones = [{ id: '11eddb23-1f01-4926-9af7-36d9a8938ae4', availability_zone_profile_id: 'f44f46ee-5f19-4515-b930-b62c9649081d', name: 'az_1', description: 'AZ 1 description', is_enabled: true }, { id: '2a83c5f3-c2e6-44cb-ac02-e06617c2b7ca', availability_zone_profile_id: '52dacdb9-c20d-4f49-9c0a-a957befaf27a', name: 'az_2', description: 'AZ 2 description', is_enabled: true }, { id: 'ff89a83c-3819-44e6-8383-f42d3a270f5f', availability_zone_profile_id: '9fe93b65-85cc-4f86-a2d9-45f78eb909d0', name: 'az_3', description: 'AZ 3 description', is_enabled: true }]; scope = $rootScope.$new(); scope.model = { networks: { '5d658cef-3402-4474-bb8a-0c1162efd9a9': { id: '5d658cef-3402-4474-bb8a-0c1162efd9a9', name: 'network_1' } }, flavors: { '15d990e1-3438-4073-89b8-6e4706f0b176': { id: '15d990e1-3438-4073-89b8-6e4706f0b176', name: 'flavor_1', flavor_profile_id: '79e16118-daba-4255-9d1d-9cc7812e18a1', is_enabled: true } }, availability_zones: { '11eddb23-1f01-4926-9af7-36d9a8938ae4': { id: '11eddb23-1f01-4926-9af7-36d9a8938ae4', availability_zone_profile_id: 'f44f46ee-5f19-4515-b930-b62c9649081d', name: 'az_1', description: 'AZ 1 description', is_enabled: true } }, subnets: [{}, {}], spec: { loadbalancer: { vip_subnet_id: null } }, initialized: false }; ctrl = $controller('LoadBalancerDetailsController', {$scope: scope}); spyOn(ctrl, 'buildSubnetOptions').and.callThrough(); spyOn(ctrl, 'buildFlavorOptions').and.callThrough(); spyOn(ctrl, 'buildAvailabilityZoneOptions').and.callThrough(); spyOn(ctrl, '_checkLoaded').and.callThrough(); })); it('should define error messages for invalid fields', function() { expect(ctrl.ipError).toBeDefined(); }); it('should define patterns for field validation', function() { expect(ctrl.ipPattern).toBeDefined(); }); it('should create shorthand text', function() { // Full values expect(ctrl.shorthand(mockSubnets[0])).toBe( 'network_1: 1.1.1.1/24 (subnet_1)' ); // No network name expect(ctrl.shorthand(mockSubnets[1])).toBe( '12345678-0...: 2.2.2.2/16 (subnet_2)' ); // No network and subnet names expect(ctrl.shorthand(mockSubnets[2])).toBe( '12345678-0...: 2.2.2.2/16 (d8056c7e-c...)' ); }); it('should create flavor shorthand text', function() { expect(ctrl.flavorShorthand(mockFlavors[0])).toBe( 'flavor_1: Flavor 1 description' ); expect(ctrl.flavorShorthand(mockFlavors[1])).toBe( 'flavor_2: ' ); expect(ctrl.flavorShorthand(mockFlavors[2])).toBe( '94306089-5...: ' ); }); it('should create az shorthand text', function() { expect(ctrl.availabilityZoneShorthand(mockAvailabilityZones[0])).toBe( 'az_1' ); expect(ctrl.availabilityZoneShorthand(mockAvailabilityZones[1])).toBe( 'az_2' ); expect(ctrl.availabilityZoneShorthand(mockAvailabilityZones[2])).toBe( 'az_3' ); }); it('should set subnet', function() { ctrl.setSubnet(mockSubnets[0]); expect(scope.model.spec.loadbalancer.vip_subnet_id).toBe(mockSubnets[0]); ctrl.setSubnet(null); expect(scope.model.spec.loadbalancer.vip_subnet_id).toBe(null); }); it('should set flavor', function() { ctrl.setFlavor(mockFlavors[0]); expect(scope.model.spec.loadbalancer.flavor_id).toBe(mockFlavors[0]); ctrl.setFlavor(null); expect(scope.model.spec.loadbalancer.flavor_id).toBe(null); }); it('should set availability zone', function() { ctrl.setAvailabilityZone(mockAvailabilityZones[0]); expect(scope.model.spec.loadbalancer.availability_zone).toBe(mockAvailabilityZones[0]); ctrl.setAvailabilityZone(null); expect(scope.model.spec.loadbalancer.availability_zone).toBe(null); }); it('should initialize watchers', function() { ctrl.$onInit(); scope.model.subnets = []; scope.$apply(); expect(ctrl._checkLoaded).toHaveBeenCalled(); scope.model.networks = {}; scope.$apply(); expect(ctrl._checkLoaded).toHaveBeenCalled(); scope.model.flavors = {}; scope.$apply(); expect(ctrl._checkLoaded).toHaveBeenCalled(); scope.model.availability_zones = {}; scope.$apply(); expect(ctrl._checkLoaded).toHaveBeenCalled(); scope.model.initialized = true; scope.$apply(); expect(ctrl._checkLoaded).toHaveBeenCalled(); }); it('should initialize networks watcher', function() { ctrl.$onInit(); scope.model.networks = {}; scope.$apply(); //expect(ctrl.buildSubnetOptions).toHaveBeenCalled(); }); it('should build subnetOptions', function() { ctrl.buildSubnetOptions(); expect(ctrl.subnetOptions).not.toBe(scope.model.subnets); expect(ctrl.subnetOptions).toEqual(scope.model.subnets); }); it('should produce column data', function() { expect(ctrl.subnetColumns).toBeDefined(); var networkLabel1 = ctrl.subnetColumns[0].value(mockSubnets[0]); expect(networkLabel1).toBe('network_1'); var networkLabel2 = ctrl.subnetColumns[0].value(mockSubnets[1]); expect(networkLabel2).toBe(''); expect(ctrl.subnetColumns[1].label).toBe('Network ID'); expect(ctrl.subnetColumns[1].value).toBe('network_id'); expect(ctrl.subnetColumns[2].label).toBe('Subnet'); expect(ctrl.subnetColumns[2].value).toBe('name'); expect(ctrl.subnetColumns[3].label).toBe('Subnet ID'); expect(ctrl.subnetColumns[3].value).toBe('id'); expect(ctrl.subnetColumns[4].label).toBe('CIDR'); expect(ctrl.subnetColumns[4].value).toBe('cidr'); }); it('should react to data being loaded', function() { ctrl._checkLoaded(); expect(ctrl.buildSubnetOptions).not.toHaveBeenCalled(); expect(ctrl.dataLoaded).toBe(false); scope.model.initialized = true; ctrl._checkLoaded(); expect(ctrl.buildSubnetOptions).toHaveBeenCalled(); expect(ctrl.dataLoaded).toBe(true); }); it('should initialize flavors watcher', function() { ctrl.$onInit(); scope.model.flavors = {}; scope.$apply(); //expect(ctrl.buildSubnetOptions).toHaveBeenCalled(); }); it('should initialize availability zone watcher', function() { ctrl.$onInit(); scope.model.availability_zones = {}; scope.$apply(); //expect(ctrl.buildSubnetOptions).toHaveBeenCalled(); }); it('should produce flavor column data', function() { expect(ctrl.flavorColumns).toBeDefined(); expect(ctrl.flavorColumns[0].label).toBe('Flavor'); expect(ctrl.flavorColumns[0].value).toBe('name'); expect(ctrl.flavorColumns[1].label).toBe('Flavor ID'); expect(ctrl.flavorColumns[1].value).toBe('id'); expect(ctrl.flavorColumns[2].label).toBe('Flavor Description'); expect(ctrl.flavorColumns[2].value).toBe('description'); }); it('should produce availability zone column data', function() { expect(ctrl.availabilityZoneColumns).toBeDefined(); expect(ctrl.availabilityZoneColumns[0].label).toBe('Availability Zone'); expect(ctrl.availabilityZoneColumns[0].value).toBe('name'); }); }); }); })(); ././@PaxHeader0000000000000000000000000000023500000000000010215 xustar00135 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.help.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000664000175100017510000000107115033037474032737 0ustar00mylesmyles

The load balancer occupies a neutron network port and has an IP address assigned from a subnet.

IP address: If an IP address is provided it must be a well-formed IPv4 or IPv6 address. The system will attempt to assign the provided IP address to the load balancer. If an IP address is not provided then one will be allocated for you.

Subnet: The network on which to allocate the load balancer's IP address.

././@PaxHeader0000000000000000000000000000023000000000000010210 xustar00130 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000664000175100017510000000777715033037474032762 0ustar00mylesmyles

Provide the details for the load balancer.

{$ ::ctrl.ipError $}
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4721007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/0000775000175100017510000000000015033037476032371 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022700000000000010216 xustar00129 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/me0000664000175100017510000001104415033037474032713 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .controller('MemberDetailsController', MemberDetailsController); MemberDetailsController.$inject = [ '$scope', '$compile', 'horizon.dashboard.project.lbaasv2.popovers', 'horizon.dashboard.project.lbaasv2.patterns', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name MemberDetailsController * @description * The `MemberDetailsController` controller provides functions for adding members to a pool. * @param $scope The angular scope object. * @param $compile The angular compile service. * @param popoverTemplates LBaaS v2 popover templates constant. * @param patterns The LBaaS v2 patterns constant. * @param gettext The horizon gettext function for translation. * @returns undefined */ function MemberDetailsController($scope, $compile, popoverTemplates, patterns, gettext) { var ctrl = this; var memberCounter = 0; // Error text for invalid fields ctrl.portError = gettext('The port must be a number between 1 and 65535.'); ctrl.weightError = gettext('The weight must be a number between 0 and 256.'); ctrl.ipError = gettext('The IP address is not valid.'); // Instances transer table widget properties ctrl.tableData = { available: $scope.model.members, allocated: $scope.model.spec.members, displayedAvailable: [], displayedAllocated: [] }; ctrl.tableLimits = { maxAllocation: -1 }; ctrl.tableHelp = { availHelpText: '', noneAllocText: gettext('No members have been allocated'), noneAvailText: gettext('No available instances'), allocTitle: gettext('Allocated Members'), availTitle: gettext('Available Instances') }; // IP address validation pattern ctrl.ipPattern = [patterns.ipv4, patterns.ipv6].join('|'); // Functions to control the IP address popover ctrl.showAddressPopover = showAddressPopover; ctrl.hideAddressPopover = hideAddressPopover; ctrl.addressPopoverTarget = addressPopoverTarget; // Member management ctrl.allocateExternalMember = allocateExternalMember; ctrl.allocateMember = allocateMember; ctrl.deallocateMember = deallocateMember; ctrl.getSubnetName = getSubnetName; ////////// function showAddressPopover(event, member) { var element = angular.element(event.target); var scope = $scope.$new(true); scope.member = member; element.popover({ content: $compile(popoverTemplates.ipAddresses)(scope), html: true, placement: 'top', title: interpolate(gettext('IP Addresses (%(count)s)'), { count: member.addresses.length }, true) }); element.popover('show'); } function hideAddressPopover(event) { var element = angular.element(event.target); element.popover('hide'); } function addressPopoverTarget(member) { return interpolate(gettext('%(ip)s...'), { ip: member.address.ip }, true); } function allocateExternalMember() { var protocol = $scope.model.spec.pool.protocol; $scope.model.spec.members.push({ id: memberCounter++, address: null, subnet_id: null, protocol_port: { HTTP: 80 }[protocol], weight: 1, monitor_address: null, monitor_port: null, admin_state_up: true, backup: false, name: null }); } function allocateMember(member) { var newMember = angular.extend(angular.copy(member), { id: memberCounter++ }); $scope.model.spec.members.push(newMember); } function deallocateMember(member) { var index = $scope.model.spec.members.indexOf(member); $scope.model.spec.members.splice(index, 1); } function getSubnetName(member) { return $scope.model.subnets.filter(function filterSubnet(subnet) { return subnet.id === member.address.subnet; })[0].name; } } })(); ././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00134 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/me0000664000175100017510000001057215033037474032720 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function() { 'use strict'; describe('Member Details Step', function() { var model, ctrl; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(function() { model = { spec: { members: [], pool: { protocol: 'HTTP' } }, members: [{ id: '1', name: 'foo', description: 'bar', weight: 1, protocol_port: 80, address: { ip: '1.2.3.4', subnet: '1' }, addresses: [{ ip: '1.2.3.4', subnet: '1' }, { ip: '2.3.4.5', subnet: '2' }] }], subnets: [{ id: '1', name: 'subnet-1' }] }; }); beforeEach(inject(function($controller, $rootScope) { var scope = $rootScope.$new(); scope.model = model; ctrl = $controller('MemberDetailsController', { $scope: scope }); $.fn.popover = angular.noop; spyOn($.fn, 'popover'); })); it('should define error messages for invalid fields', function() { expect(ctrl.portError).toBeDefined(); expect(ctrl.weightError).toBeDefined(); expect(ctrl.ipError).toBeDefined(); }); it('should define patterns for validation', function() { expect(ctrl.ipPattern).toBeDefined(); }); it('should define transfer table properties', function() { expect(ctrl.tableData).toBeDefined(); expect(ctrl.tableLimits).toBeDefined(); expect(ctrl.tableHelp).toBeDefined(); }); it('should have available members', function() { expect(ctrl.tableData.available).toBeDefined(); expect(ctrl.tableData.available.length).toBe(1); expect(ctrl.tableData.available[0].id).toBe('1'); }); it('should not have allocated members', function() { expect(ctrl.tableData.allocated).toEqual([]); }); it('should allow adding multiple members', function() { expect(ctrl.tableLimits.maxAllocation).toBe(-1); }); it('should properly format address popover target', function() { var target = ctrl.addressPopoverTarget(model.members[0]); expect(target).toBe('1.2.3.4...'); }); it('should allocate a new external member', function() { ctrl.allocateExternalMember(); expect(model.spec.members.length).toBe(1); expect(model.spec.members[0].id).toBe(0); expect(model.spec.members[0].address).toBeNull(); expect(model.spec.members[0].subnet_id).toBeNull(); }); it('should allocate a given member', function() { ctrl.allocateMember(model.members[0]); expect(model.spec.members.length).toBe(1); expect(model.spec.members[0].id).toBe(0); expect(model.spec.members[0].address).toEqual(model.members[0].address); expect(model.spec.members[0].subnet_id).toBeUndefined(); expect(model.spec.members[0].protocol_port).toEqual(model.members[0].protocol_port); }); it('should deallocate a given member', function() { ctrl.deallocateMember(model.spec.members[0]); expect(model.spec.members.length).toBe(0); }); it('should show subnet name for available instance', function() { var name = ctrl.getSubnetName(model.members[0]); expect(name).toBe('subnet-1'); }); it('should show IP addresses popover', function() { ctrl.showAddressPopover({ target: 'foo' }, model.members[0]); expect($.fn.popover.calls.count()).toBe(2); expect($.fn.popover.calls.argsFor(0)[0]).toEqual({ content: jasmine.any(Object), html: true, placement: 'top', title: 'IP Addresses (2)' }); expect($.fn.popover.calls.argsFor(1)[0]).toBe('show'); }); it('should hide IP addresses popover', function() { ctrl.hideAddressPopover({ target: 'foo' }); expect($.fn.popover).toHaveBeenCalledWith('hide'); }); }); })(); ././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.help.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/me0000664000175100017510000000355615033037474032724 0ustar00mylesmyles

Members are the actual IP addresses that will receive traffic from the load balancer. Each member must have a unique combination of IP address and port.

The Available Instances table contains existing compute instances that can be added as members of the pool. Use the "Add external member" button to add a member not found in the Available Instances table.

IP address: The IP address of the member to receive traffic from the load balancer. Must be a well-formed IPv4 or IPv6 address.

Subnet: The network which contains the IP address of the member.

Port: The port on which the member listens for traffic. Must be a number from 1 to 65535.

Weight: The weight of a member determines the portion of requests or connections it services compared to the other members of the pool. A value of 0 means the member does not receive new connections but continues to service existing connections. A higher weight means it will receive more traffic. Must be a number from 0 to 256.

Monitor Address: An alternate IP address used for health monitoring a backend member. Default is null which monitors the member address.

Monitor Port: An alternate protocol port used for health monitoring a backend member. Default is null which monitors the member protocol port.

Backup: Is the member a backup? Backup members only receive traffic when all non-backup members are down.

././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00120 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/me0000664000175100017510000003215015033037474032714 0ustar00mylesmyles

Add members to the load balancer pool.

IP Address Subnet Port Weight
{$ ::trCtrl.helpText.noneAllocText $}
{$ row.address.ip $}
{$ ctrl.getSubnetName(row) $}
Remove
Monitor Address
Monitor Port
Admin State Up
Backup
Name
Add external member
Name IP Address
{$ ::trCtrl.helpText.noneAvailText $}
{$ ::row.name $} {$ row.address.ip $} {$ ctrl.addressPopoverTarget(row) $} Add
././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.serv0000664000175100017510000000637615033037474032746 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function() { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .factory('horizon.dashboard.project.lbaasv2.workflow.modal', modalService); modalService.$inject = [ '$rootScope', 'horizon.dashboard.project.lbaasv2.events', '$uibModal', 'horizon.framework.widgets.toast.service' ]; /** * @ngdoc service * @ngname horizon.dashboard.project.lbaasv2.workflow.modal * * @description * Provides the service for opening the LBaaS create / edit modal. * * @param $rootScope The angular root scope object. * @param events The LBaaS v2 events object. * @param $uibModal The angular bootstrap $uibModal service. * @param toastService The horizon toast service. * @returns The modal service for the LBaaS workflow. */ function modalService($rootScope, events, $uibModal, toastService) { var service = { init: init }; return service; ////////////// /** * @ngdoc method * @name init * * @description * Initialize a new scope for an LBaaS workflow modal. * * @param args An object containing the following properties: * controller*: Controller to use for the wizard instance. * message*: String to display using the toast service when wizard completes. * allowed*: Function used to determine if the workflow action is allowed. * handle: Function to call after the modal closes, receives the result of wizard submit. * @returns An object with a single function 'open', used to open the modal. */ function init(args) { return { handle: args.handle, // exposed just for testing allowed: args.allowed, perform: open }; /** * @ngdoc method * @name open * * @description * Open the modal. * * @param item The row item from the table action. * @returns undefined */ function open(item) { var spec = { size: 'lg', backdrop: 'static', controller: 'ModalContainerController', template: '', windowClass: 'modal-dialog-wizard', resolve: { launchContext: function() { return item; } } }; return $uibModal.open(spec).result.then(onModalClose); } function onModalClose(response) { toastService.add('success', args.message); if (args.handle) { $rootScope.$broadcast(events.ACTION_DONE); return args.handle(response); } return null; } } } })(); ././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00121 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.serv0000664000175100017510000000632415033037474032737 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Workflow Modal Service', function() { var modalService, modal, response; beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.framework.conf')); beforeEach(module('horizon.framework.widgets.toast')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(module(function($provide) { response = { data: { id: '1' } }; modal = { open: function() { return { result: { then: function(func) { func(response); } } }; } }; $provide.value('$uibModal', modal); })); beforeEach(inject(function ($injector) { modalService = $injector.get('horizon.dashboard.project.lbaasv2.workflow.modal'); })); it('should define an init function', function() { expect(modalService.init).toBeDefined(); }); describe('modalService "perform" function tests', function() { var toastService; beforeEach(inject(function ($injector) { toastService = $injector.get('horizon.framework.widgets.toast.service'); })); it('calls modal.open', function() { spyOn(modal, 'open').and.callThrough(); modalService.init({}).perform(); expect(modal.open).toHaveBeenCalled(); }); it('calls modal.open with expected values', function() { spyOn(modal, 'open').and.callThrough(); modalService.init({}).perform(); var args = modal.open.calls.argsFor(0)[0]; expect(args.backdrop).toBe('static'); expect(args.controller).toBeDefined(); expect(args.resolve).toBeDefined(); expect(args.resolve.launchContext).toBeDefined(); }); it('launchContext function returns argument passed to open function', function() { spyOn(modal, 'open').and.callThrough(); modalService.init({}).perform('foo'); var args = modal.open.calls.argsFor(0)[0]; expect(args.resolve.launchContext()).toBe('foo'); }); it('shows message upon success', function() { spyOn(toastService, 'add').and.callThrough(); modalService.init({ message: 'foo' }).perform(); expect(toastService.add).toHaveBeenCalledWith('success', 'foo'); }); it('handles response upon success', function() { spyOn(toastService, 'add').and.callThrough(); var args = { handle: angular.noop }; spyOn(args, 'handle'); modalService.init(args).perform(); expect(args.handle).toHaveBeenCalledWith(response); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.serv0000664000175100017510000007656615033037474032762 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function () { 'use strict'; var push = Array.prototype.push; angular .module('horizon.dashboard.project.lbaasv2') .factory('horizon.dashboard.project.lbaasv2.workflow.model', workflowModel); workflowModel.$inject = [ '$q', 'horizon.app.core.openstack-service-api.neutron', 'horizon.app.core.openstack-service-api.nova', 'horizon.app.core.openstack-service-api.lbaasv2', 'horizon.app.core.openstack-service-api.octavia-barbican', 'horizon.app.core.openstack-service-api.serviceCatalog', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc service * @name horizon.dashboard.project.lbaasv2.workflow.model * * @description * This is the M part of the MVC design pattern for the LBaaS wizard workflow. It is responsible * for providing data to the view of each step in the workflow and collecting the user's input * from the view. It is also the center point of communication between the UI and services API. * * @param $q The angular service for promises. * @param neutronAPI The neutron service API. * @param novaAPI The nova service API. * @param lbaasv2API The LBaaS V2 service API. * @param octaviaBarbicanAPI The octavia barbican service API. * @param serviceCatalog The keystone service catalog API. * @param gettext The horizon gettext function for translation. * @returns The model service for the create load balancer workflow. */ function workflowModel( $q, neutronAPI, novaAPI, lbaasv2API, octaviaBarbicanAPI, serviceCatalog, gettext ) { var ports, keymanagerPromise; /** * @ngdoc model api object */ var model = { initializing: false, initialized: false, context: null, /** * @name spec * * @description * A dictionary like object containing specification collected from user * input. */ spec: null, subnets: [], members: [], networks: {}, flavors: {}, listenerProtocols: ['HTTP', 'TCP', 'TERMINATED_HTTPS', 'HTTPS', 'UDP', 'SCTP'], availability_zones: {}, l7policyActions: ['REJECT', 'REDIRECT_TO_URL', 'REDIRECT_TO_POOL'], l7ruleTypes: ['HOST_NAME', 'PATH', 'FILE_TYPE', 'HEADER', 'COOKIE'], l7ruleCompareTypes: ['REGEX', 'EQUAL_TO', 'STARTS_WITH', 'ENDS_WITH', 'CONTAINS'], l7ruleFileTypeCompareTypes: ['REGEX', 'EQUAL_TO'], poolProtocols: ['HTTP', 'HTTPS', 'PROXY', 'PROXYV2', 'TCP', 'UDP', 'SCTP'], methods: ['LEAST_CONNECTIONS', 'ROUND_ROBIN', 'SOURCE_IP'], types: ['SOURCE_IP', 'HTTP_COOKIE', 'APP_COOKIE'], monitorTypes: ['HTTP', 'HTTPS', 'PING', 'TCP', 'TLS-HELLO', 'UDP-CONNECT', 'SCTP'], monitorMethods: ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PATCH', 'CONNECT'], certificates: [], listenerPorts: [], yesNoOptions: [ { label: gettext('Yes'), value: true }, { label: gettext('No'), value: false } ], /** * api methods for UI controllers */ initialize: initialize, submit: submit }; return model; /////////////// /** * @ngdoc method * @name workflowModel.initialize * @returns {promise} * * @description * Send request to get all data to initialize the model. * * @param resource Resource type being created / edited, one of 'loadbalancer', 'listener', * 'pool', 'monitor', or 'members'. * @param id ID of the resource being edited. */ function initialize(resource, id, loadBalancerId, parentResourceId) { var promise; model.certificatesError = false; model.context = { resource: resource, id: id, submit: null, create_listener: true, create_pool: true, create_monitor: true }; model.certificates = []; model.listenerPorts = []; model.spec = { loadbalancer_id: loadBalancerId, parentResourceId: parentResourceId, loadbalancer: { name: null, description: null, vip_address: null, vip_subnet_id: null, flavor_id: null, availability_zone: null, admin_state_up: true }, listener: { id: null, name: null, description: null, protocol: null, protocol_port: null, connection_limit: -1, admin_state_up: true, default_pool: null, default_pool_id: null, insert_headers: {}, timeout_client_data: 50000, timeout_member_connect: 5000, timeout_member_data: 50000, timeout_tcp_inspect: 0, allowed_cidrs: null, tls_ciphers: null }, l7policy: { id: null, name: null, description: null, action: null, position: null, redirect_pool_id: null, redirect_url: null, admin_state_up: true }, l7rule: { id: null, type: null, compare_type: null, key: null, rule_value: null, invert: false, admin_state_up: true }, pool: { id: null, name: null, description: null, protocol: null, lb_algorithm: null, session_persistence: { type: null, cookie_name: null }, admin_state_up: true, tls_enabled: false, tls_ciphers: null }, monitor: { id: null, name: null, type: null, delay: 5, max_retries: 3, max_retries_down: 3, timeout: 5, http_method: 'GET', expected_codes: '200', url_path: '/', admin_state_up: true }, members: [], certificates: [], availablePools: [] }; if (!model.initializing) { model.initializing = true; promise = initializeResources(); } return promise; } function initializeResources() { var type = (model.context.id ? 'edit' : 'create') + model.context.resource; keymanagerPromise = serviceCatalog.ifTypeEnabled('key-manager'); if (type === 'createloadbalancer' || model.context.resource === 'listener') { keymanagerPromise.then(angular.noop, certificatesNotSupported); } var promise = { createloadbalancer: initCreateLoadBalancer, createlistener: initCreateListener, createl7policy: initCreateL7Policy, createl7rule: initCreateL7Rule, createpool: initCreatePool, createmonitor: initCreateMonitor, createmembers: initUpdateMemberList, editloadbalancer: initEditLoadBalancer, editlistener: initEditListener, editl7policy: initEditL7Policy, editl7rule: initEditL7Rule, editpool: initEditPool, editmonitor: initEditMonitor }[type](keymanagerPromise); return promise.then(onInitSuccess, onInitFail); } function onInitSuccess() { model.initializing = false; model.initialized = true; } function onInitFail() { model.initializing = false; model.initialized = false; } function initCreateLoadBalancer(keymanagerPromise) { model.context.submit = createLoadBalancer; return $q.all([ lbaasv2API.getFlavors().then(onGetFlavors), lbaasv2API.getAvailabilityZones().then(onGetAvailabilityZones), neutronAPI.getSubnets().then(onGetSubnets), neutronAPI.getPorts().then(onGetPorts), neutronAPI.getNetworks().then(onGetNetworks), novaAPI.getServers().then(onGetServers), keymanagerPromise.then(prepareCertificates, angular.noop) ]).then(initMemberAddresses); } function onGetNetworks(response) { angular.forEach(response.data.items, function(value) { model.networks[value.id] = value; }); } function onGetFlavors(response) { angular.forEach(response.data.items, function(value) { model.flavors[value.id] = value; }); } function onGetAvailabilityZones(response) { angular.forEach(response.data.items, function(value) { model.availability_zones[value.name] = value; }); } function initCreateListener(keymanagerPromise) { model.context.submit = createListener; return $q.all([ lbaasv2API.getListeners(model.spec.loadbalancer_id).then(onGetListeners), neutronAPI.getSubnets().then(onGetSubnets), neutronAPI.getPorts().then(onGetPorts), novaAPI.getServers().then(onGetServers), keymanagerPromise.then(prepareCertificates, angular.noop) ]).then(initMemberAddresses); } function initCreateL7Policy() { model.context.submit = createL7Policy; return lbaasv2API.getListener(model.spec.parentResourceId) .then(onGetListener).then(getPools).then(onGetPools); } function initCreateL7Rule() { model.context.submit = createL7Rule; return $q.when(); } function initCreatePool() { model.context.submit = createPool; // We get the listener details here because we need to know the listener protocol // in order to default the new pool's protocol to match. if (model.spec.parentResourceId) { return $q.all([ lbaasv2API.getListener(model.spec.parentResourceId).then(onGetListener), neutronAPI.getSubnets().then(onGetSubnets), neutronAPI.getPorts().then(onGetPorts), novaAPI.getServers().then(onGetServers) ]).then(initMemberAddresses); } else { return $q.all([ neutronAPI.getSubnets().then(onGetSubnets), neutronAPI.getPorts().then(onGetPorts), novaAPI.getServers().then(onGetServers) ]).then(initMemberAddresses); } } function initCreateMonitor() { model.context.submit = createHealthMonitor; return $q.when(); } function initUpdateMemberList() { model.context.submit = updatePoolMemberList; return $q.all([ lbaasv2API.getPool(model.spec.parentResourceId).then(onGetPool), neutronAPI.getSubnets().then(onGetSubnets).then(getMembers).then(onGetMembers), neutronAPI.getPorts().then(onGetPorts), novaAPI.getServers().then(onGetServers) ]).then(initMemberAddresses); } function initEditLoadBalancer() { model.context.submit = editLoadBalancer; return $q.all([ lbaasv2API.getFlavors().then(onGetFlavors), lbaasv2API.getAvailabilityZones().then(onGetAvailabilityZones), lbaasv2API.getLoadBalancer(model.context.id).then(onGetLoadBalancer), neutronAPI.getSubnets().then(onGetSubnets), neutronAPI.getNetworks().then(onGetNetworks) ]).then(initSubnet).then(initFlavor).then(initAvailabilityZone); } function initEditListener() { model.context.submit = editListener; return $q.all([ neutronAPI.getSubnets().then(onGetSubnets).then(getListener) .then(onGetListener).then(getPools).then(onGetPools), neutronAPI.getPorts().then(onGetPorts), novaAPI.getServers().then(onGetServers) ]).then(initMemberAddresses); } function initEditL7Policy() { model.context.submit = editL7Policy; return lbaasv2API .getListener(model.spec.parentResourceId).then(onGetListener) .then(getPools).then(onGetPools) .then(getL7Policy).then(onGetL7Policy); } function initEditL7Rule() { model.context.submit = editL7Rule; return getL7Rule().then(onGetL7Rule); } function initEditPool() { model.context.submit = editPool; return $q.all([ neutronAPI.getSubnets().then(onGetSubnets).then(getPool).then(onGetPool), neutronAPI.getPorts().then(onGetPorts), novaAPI.getServers().then(onGetServers) ]).then(initMemberAddresses); } function initEditMonitor() { model.context.submit = editHealthMonitor; return lbaasv2API.getHealthMonitor(model.context.id).then(onGetHealthMonitor); } /** * @ngdoc method * @name workflowModel.submit * @returns {promise} * * @description * Send request for completing the wizard. * * @returns Response from the LBaaS V2 API. */ function submit() { var finalSpec = angular.copy(model.spec); cleanFinalSpecLoadBalancer(finalSpec); cleanFinalSpecListener(finalSpec); cleanFinalSpecPool(finalSpec); cleanFinalSpecMembers(finalSpec); cleanFinalSpecMonitor(finalSpec); removeNulls(finalSpec); return model.context.submit(finalSpec); } function createLoadBalancer(spec) { return lbaasv2API.createLoadBalancer(spec); } function createListener(spec) { return lbaasv2API.createListener(spec); } function createL7Policy(spec) { return lbaasv2API.createL7Policy(spec); } function createL7Rule(spec) { return lbaasv2API.createL7Rule(model.spec.parentResourceId, spec); } function createPool(spec) { return lbaasv2API.createPool(spec); } function createHealthMonitor(spec) { return lbaasv2API.createHealthMonitor(spec); } function editLoadBalancer(spec) { return lbaasv2API.editLoadBalancer(model.context.id, spec); } function editListener(spec) { return lbaasv2API.editListener(model.context.id, spec); } function editL7Policy(spec) { return lbaasv2API.editL7Policy(model.context.id, spec); } function editL7Rule(spec) { return lbaasv2API.editL7Rule(model.spec.parentResourceId, model.context.id, spec); } function editPool(spec) { return lbaasv2API.editPool(model.context.id, spec); } function editHealthMonitor(spec) { return lbaasv2API.editHealthMonitor(model.context.id, spec); } function updatePoolMemberList(spec) { return lbaasv2API.updateMemberList(model.spec.parentResourceId, spec); } function cleanFinalSpecLoadBalancer(finalSpec) { var context = model.context; if (angular.isObject(finalSpec.loadbalancer.flavor_id)) { finalSpec.loadbalancer.flavor_id = finalSpec.loadbalancer.flavor_id.id; } if (angular.isObject(finalSpec.loadbalancer.availability_zone)) { finalSpec.loadbalancer.availability_zone = finalSpec.loadbalancer.availability_zone.name; } // Load balancer requires vip_subnet_id if (!finalSpec.loadbalancer.vip_subnet_id) { delete finalSpec.loadbalancer; } else { finalSpec.loadbalancer.vip_subnet_id = finalSpec.loadbalancer.vip_subnet_id.id; } // Cannot edit the IP or subnet if (context.resource === 'loadbalancer' && context.id) { delete finalSpec.flavor_id; delete finalSpec.availability_zone; delete finalSpec.vip_subnet_id; delete finalSpec.vip_address; } } function cleanFinalSpecListener(finalSpec) { if (!finalSpec.listener.protocol || !finalSpec.listener.protocol_port) { // Listener requires protocol and port delete finalSpec.listener; delete finalSpec.certificates; } else { for (var header in finalSpec.listener.insert_headers) { if (!finalSpec.listener.insert_headers[header]) { delete finalSpec.listener.insert_headers[header]; } } if (finalSpec.listener.protocol !== 'TERMINATED_HTTPS') { // Remove certificate containers if not using TERMINATED_HTTPS delete finalSpec.certificates; delete finalSpec.listener.tls_ciphers; } else { var containers = []; angular.forEach(finalSpec.certificates, function(cert) { containers.push(cert.id); }); finalSpec.certificates = containers; } } } function cleanFinalSpecPool(finalSpec) { // Pool requires method if (!finalSpec.pool.lb_algorithm) { delete finalSpec.pool; } else { // The pool protocol must be HTTP if the listener protocol is TERMINATED_HTTPS and // otherwise has to match it. var protocol = finalSpec.listener ? finalSpec.listener.protocol : finalSpec.pool.protocol; finalSpec.pool.protocol = protocol === 'TERMINATED_HTTPS' ? 'HTTP' : protocol; if (!finalSpec.pool.tls_enabled) { delete finalSpec.pool.tls_ciphers; } if (angular.isObject(finalSpec.pool.session_persistence)) { if (!finalSpec.pool.session_persistence.type) { finalSpec.pool.session_persistence = null; } else if (finalSpec.pool.session_persistence.type !== 'APP_COOKIE') { finalSpec.pool.session_persistence.cookie_name = null; } } } } function cleanFinalSpecMembers(finalSpec) { if (finalSpec.members.length === 0) { delete finalSpec.members; return; } var members = []; angular.forEach(finalSpec.members, function cleanMember(member) { if (member.address && member.protocol_port) { var propsToRemove = ['description', 'addresses', 'allocatedMember']; propsToRemove.forEach(function deleteProperty(prop) { if (angular.isDefined(member[prop])) { delete member[prop]; } }); if (angular.isObject(member.address)) { member.subnet_id = member.address.subnet; member.address = member.address.ip; } else if (member.subnet_id) { member.subnet_id = member.subnet_id.id; } else { delete member.subnet_id; } members.push(member); } }); if (members.length > 0) { finalSpec.members = members; } else { delete finalSpec.members; } } function cleanFinalSpecMonitor(finalSpec) { // Monitor requires delay, max_retries, and timeout if (!angular.isNumber(finalSpec.monitor.delay) || !angular.isNumber(finalSpec.monitor.max_retries) || !angular.isNumber(finalSpec.monitor.timeout)) { delete finalSpec.monitor; return; } // Only include necessary monitor properties if (finalSpec.monitor.type !== 'HTTP' && finalSpec.monitor.type !== 'HTTPS') { delete finalSpec.monitor.http_method; delete finalSpec.monitor.expected_codes; delete finalSpec.monitor.url_path; } } function removeNulls(finalSpec) { angular.forEach(finalSpec, function deleteNullsForGroup(group, groupName) { angular.forEach(group, function deleteNullValue(value, key) { if (value === null) { delete finalSpec[groupName][key]; } }); }); } function onGetListeners(response) { angular.forEach(response.data.items, function addPort(listener) { model.listenerPorts.push(listener.protocol_port); }); } function onGetPools(response) { angular.forEach(response.data.items, function addPool(pool) { if (pool.listeners.length > 0 && pool.listeners[0].id !== model.spec.listener.id) { return; } var p = pool.id + '(' + pool.name + ')'; if (pool.protocol === model.spec.listener.protocol) { model.spec.availablePools.push(p); } else if (pool.protocol === 'HTTP' && model.spec.listener.protocol === 'TERMINATED_HTTPS') { model.spec.availablePools.push(p); } }); } function onGetSubnets(response) { model.subnets.length = 0; push.apply(model.subnets, response.data.items); } function onGetServers(response) { model.members.length = 0; var members = []; angular.forEach(response.data.items, function addMember(server) { // If the server is in a state where it does not have an IP address then we can't use it if (server.addresses && !angular.equals({}, server.addresses)) { members.push({ id: server.id, name: server.name, weight: 1, monitor_address: null, monitor_port: null, admin_state_up: true, backup: false }); } }); push.apply(model.members, members); } function onGetPorts(response) { ports = response.data.items; } function onGetMembers(response) { setMembersSpec(response.data.items); } function initMemberAddresses() { angular.forEach(model.members, function initAddresses(member) { var memberPorts = ports.filter(function filterPortByDevice(port) { return port.device_id === member.id; }); member.addresses = []; angular.forEach(memberPorts, function addAddressesForPort(port) { angular.forEach(port.fixed_ips, function addAddress(ip) { member.addresses.push({ ip: ip.ip_address, subnet: ip.subnet_id }); }); }); member.address = member.addresses[0]; if (model.spec.pool.protocol) { member.protocol_port = {HTTP: 80}[model.spec.pool.protocol]; } }); } function getListener() { return lbaasv2API.getListener(model.context.id, true); } function getL7Policy() { return lbaasv2API.getL7Policy(model.context.id, true); } function getL7Rule() { return lbaasv2API.getL7Rule(model.spec.parentResourceId, model.context.id); } function getPool() { return lbaasv2API.getPool(model.context.id, true); } function getPools() { return lbaasv2API.getPools(model.spec.loadbalancer_id); } function getMembers() { return lbaasv2API.getMembers(model.spec.parentResourceId); } function onGetLoadBalancer(response) { var loadbalancer = response.data; setLoadBalancerSpec(loadbalancer); } function onGetListener(response) { var result = response.data; setListenerSpec(result.listener || result); if (result.listener) { model.spec.loadbalancer_id = result.listener.load_balancers[0].id; if (result.listener.protocol === 'TERMINATED_HTTPS') { keymanagerPromise.then(prepareCertificates).then(function addAvailableCertificates() { var ref = result.listener.default_tls_container_ref; model.certificates.filter(function matchCertificate(cert) { return cert.id === ref; }).forEach(function addCertificate(cert) { model.spec.certificates.push(cert); }); }, certificatesError); $('#wizard-side-nav ul li:last').show(); } } if (result.pool) { setPoolSpec(result.pool); if (result.members) { setMembersSpec(result.members); } if (result.monitor) { setMonitorSpec(result.monitor); } } } function onGetL7Policy(response) { var result = response.data; setL7PolicySpec(result.l7policy || result); } function onGetL7Rule(response) { var result = response.data; setL7RuleSpec(result.l7rule || result); } function onGetPool(response) { var result = response.data; setPoolSpec(result.pool || result); if (result.pool) { if (result.members) { setMembersSpec(result.members); } if (result.monitor) { setMonitorSpec(result.monitor); } } } function setLoadBalancerSpec(loadbalancer) { var spec = model.spec.loadbalancer; spec.name = loadbalancer.name; spec.description = loadbalancer.description; spec.vip_address = loadbalancer.vip_address; spec.vip_subnet_id = loadbalancer.vip_subnet_id; spec.flavor_id = loadbalancer.flavor_id; spec.availability_zone = loadbalancer.availability_zone; spec.admin_state_up = loadbalancer.admin_state_up; } function setListenerSpec(listener) { var spec = model.spec.listener; spec.id = listener.id; spec.name = listener.name; spec.description = listener.description; spec.protocol = listener.protocol; spec.protocol_port = listener.protocol_port; spec.connection_limit = listener.connection_limit; spec.admin_state_up = listener.admin_state_up; spec.default_pool_id = listener.default_pool_id; spec.insert_headers = listener.insert_headers; spec.timeout_client_data = listener.timeout_client_data; spec.timeout_member_connect = listener.timeout_member_connect; spec.timeout_member_data = listener.timeout_member_data; spec.timeout_tcp_inspect = listener.timeout_tcp_inspect; spec.allowed_cidrs = listener.allowed_cidrs; spec.tls_ciphers = listener.tls_ciphers; } function setL7PolicySpec(l7policy) { var spec = model.spec.l7policy; spec.id = l7policy.id; spec.name = l7policy.name; spec.description = l7policy.description; spec.action = l7policy.action; spec.position = l7policy.position; spec.redirect_pool_id = l7policy.redirect_pool_id; spec.redirect_url = l7policy.redirect_url; spec.admin_state_up = l7policy.admin_state_up; } function setL7RuleSpec(l7rule) { var spec = model.spec.l7rule; spec.id = l7rule.id; spec.type = l7rule.type; spec.compare_type = l7rule.compare_type; spec.key = l7rule.key; spec.rule_value = l7rule.rule_value; spec.invert = l7rule.invert; spec.admin_state_up = l7rule.admin_state_up; } function setPoolSpec(pool) { var spec = model.spec.pool; spec.id = pool.id; spec.name = pool.name; spec.description = pool.description; spec.protocol = pool.protocol; spec.lb_algorithm = pool.lb_algorithm; spec.admin_state_up = pool.admin_state_up; spec.session_persistence = pool.session_persistence; spec.tls_enabled = pool.tls_enabled; spec.tls_ciphers = pool.tls_ciphers; } function setMembersSpec(membersList) { model.spec.members.length = 0; var members = []; angular.forEach(membersList, function addMember(member) { members.push({ id: member.id, address: member.address, subnet_id: mapSubnetObj(member.subnet_id), protocol_port: member.protocol_port, weight: member.weight, monitor_address: member.monitor_address, monitor_port: member.monitor_port, admin_state_up: member.admin_state_up, backup: member.backup, name: member.name, allocatedMember: true }); }); push.apply(model.spec.members, members); } function setMonitorSpec(monitor) { var spec = model.spec.monitor; spec.id = monitor.id; spec.type = monitor.type; spec.delay = monitor.delay; spec.timeout = monitor.timeout; spec.max_retries = monitor.max_retries; spec.max_retries_down = monitor.max_retries_down; spec.http_method = monitor.http_method; spec.expected_codes = monitor.expected_codes; spec.url_path = monitor.url_path; spec.admin_state_up = monitor.admin_state_up; spec.name = monitor.name; } function onGetHealthMonitor(response) { setMonitorSpec(response.data); } function prepareCertificates() { return $q.all([ octaviaBarbicanAPI.getCertificates(true), octaviaBarbicanAPI.getSecrets(true) ]).then(onGetCertificates, certificatesError); } function onGetCertificates(results) { // To use the TERMINATED_HTTPS protocol with a listener, the LBaaS v2 API wants a default // container ref and a list of containers that hold TLS secrets. In barbican the container // object has a list of references to the secrets it holds. This assumes that each // certificate container has exactly one certificate and private key. We fetch both the // certificate containers and the secrets so that we can display the secret names and // expirations dates. model.certificates.length = 0; var certificates = []; // Only accept containers that have both a certificate and private_key ref var containers = results[0].data.items.filter(function validateContainer(container) { container.refs = {}; container.secret_refs.forEach(function(ref) { container.refs[ref.name] = ref.secret_ref; }); return 'certificate' in container.refs && 'private_key' in container.refs; }); var certHrefs = []; var secrets = {}; results[1].data.items.forEach(function addSecret(secret) { secrets[secret.secret_ref] = secret; }); containers.forEach(function addCertificateContainer(container) { var secret = secrets[container.refs.certificate]; certificates.push({ id: container.container_ref, name: secret.name || secret.secret_ref.split('/').reverse()[0], expiration: secret.expiration }); certHrefs.push(secret.secret_ref); }); // Octavia now supports pkcs12 bundles which are stored as secrets. // If the secret hasn't already been loaded, add it to the list. for (var key in secrets) { if (secrets[key].secret_type !== "opaque") {continue;} var cert = { id: key, name: secrets[key].name || key, expiration: secrets[key].expiration }; if (certHrefs.indexOf(key) === -1) { certificates.push(cert); certHrefs.push(key); } } push.apply(model.certificates, certificates); } function initSubnet() { var subnet = model.subnets.filter(function filterSubnetsByLoadBalancer(s) { return s.id === model.spec.loadbalancer.vip_subnet_id; })[0]; model.spec.loadbalancer.vip_subnet_id = subnet; } function initFlavor() { model.spec.loadbalancer.flavor_id = model.flavors[model.spec.loadbalancer.flavor_id]; } function initAvailabilityZone() { model.spec.loadbalancer.availability_zone = model.availability_zones[ model.spec.loadbalancer.availability_zone]; } function mapSubnetObj(subnetId) { var subnet = model.subnets.filter(function mapSubnet(subnet) { return subnet.id === subnetId; }); return subnet[0]; } function certificatesNotSupported() { // This function is called if the key-manager service is not available. In that case we // cannot support the TERMINATED_HTTPS listener protocol so we hide the option if creating // a new load balancer or listener. However for editing we still need it. if (!model.context.id) { model.listenerProtocols.splice(2, 1); } } function certificatesError() { // This function is called if there is an error fetching the certificate containers or // secrets. In that case we cannot support the TERMINATED_HTTPS listener protocol but we // want to make the user aware of the error. model.certificatesError = true; } } })(); ././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00121 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.serv0000664000175100017510000030677315033037474032756 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Workflow Model Service', function() { var model, $q, scope, listenerResources, barbicanEnabled, certificatesError, mockNetworks, mockFlavors, mockAvailabilityZones; var includeChildResources = true; beforeEach(module('horizon.framework.util.i18n')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(function() { listenerResources = { listener: { admin_state_up: true, id: '1234', name: 'Listener 1', description: 'listener description', protocol: 'HTTP', protocol_port: 80, connection_limit: 999, load_balancers: [{id: '1234'}], default_tls_container_ref: 'container2', insert_headers: { 'X-Forwarded-For': 'True', 'X-Forwarded-Port': 'True', 'X-Forwarded-Proto': 'True' } }, pool: { admin_state_up: true, id: '1234', name: 'Pool 1', protocol: 'HTTP', lb_algorithm: 'ROUND_ROBIN', session_persistence: { type: 'APP_COOKIE', cookie_name: 'cookie_name' }, description: 'pool description' }, members: [ { id: '1234', address: '1.2.3.4', subnet_id: 'subnet-1', protocol_port: 80, weight: 1 }, { id: '5678', address: '5.6.7.8', subnet_id: 'subnet-1', protocol_port: 80, weight: 1 } ], monitor: { admin_state_up: true, id: '1234', type: 'HTTP', delay: 1, timeout: 1, max_retries: 1, max_retries_down: 1, http_method: 'POST', expected_codes: '200', url_path: '/test' } }; barbicanEnabled = true; certificatesError = false; mockNetworks = { a1: { name: 'network_1', id: 'a1' }, b2: { name: 'network_2', id: 'b2' } }; mockFlavors = { f1: { name: 'flavor_1', id: 'f1' }, f2: { name: 'flavor_2', id: 'f2' } }; mockAvailabilityZones = { az_1: { name: 'az_1', id: 'az1' }, az_2: { name: 'az_2', id: 'az2' } }; }); beforeEach(module(function($provide) { $provide.value('horizon.app.core.openstack-service-api.lbaasv2', { getLoadBalancers: function() { var loadbalancers = [ {id: '1234', name: 'Load Balancer 1'}, {id: '5678', name: 'Load Balancer 2'}, {id: '9012', name: 'myLoadBalancer3'} ]; var deferred = $q.defer(); deferred.resolve({data: {items: loadbalancers}}); return deferred.promise; }, getLoadBalancer: function() { var loadbalancer = { admin_state_up: true, id: '1234', name: 'Load Balancer 1', vip_address: '1.2.3.4', vip_subnet_id: 'subnet-1', flavor_id: 'flavor-1', availability_zone: 'az-1', description: '' }; var deferred = $q.defer(); deferred.resolve({data: loadbalancer}); return deferred.promise; }, getListeners: function() { var listeners = [ {id: '1234', name: 'Listener 1', protocol_port: 80}, {id: '5678', name: 'Listener 2', protocol_port: 81}, {id: '9012', name: 'myListener3', protocol_port: 82} ]; var deferred = $q.defer(); deferred.resolve({data: {items: listeners}}); return deferred.promise; }, getPools: function() { var pools = [ { id: '1234', name: 'Pool 1', listeners: ['1234'], protocol: 'HTTP' }, {id: '5678', name: 'Pool 2', listeners: [], protocol: 'HTTP'}, {id: '9012', name: 'Pool 3', listeners: [], protocol: 'HTTPS'} ]; var deferred = $q.defer(); deferred.resolve({data: {items: pools}}); return deferred.promise; }, getListener: function() { var deferred = $q.defer(); var listenerData; listenerData = includeChildResources ? listenerResources : listenerResources.listener; deferred.resolve({data: listenerData}); return deferred.promise; }, getL7Policy: function() { var l7policy = { admin_state_up: true, id: '1234', name: 'L7 Policy 1', description: 'l7 policy description', action: 'REDIRECT_TO_URL', position: 1, redirect_url: 'http://example.com' }; var deferred = $q.defer(); deferred.resolve({data: l7policy}); return deferred.promise; }, getL7Rule: function() { var l7rule = { admin_state_up: true, id: '1234', type: 'HOST_NAME', compare_type: 'EQUAL_TO', value: 'api.example.com', invert: false }; var deferred = $q.defer(); deferred.resolve({data: l7rule}); return deferred.promise; }, getPool: function() { var poolResources = angular.copy(listenerResources); delete poolResources.listener; var deferred = $q.defer(); var poolData; poolData = includeChildResources ? poolResources : poolResources.pool; deferred.resolve({data: poolData}); return deferred.promise; }, getMembers: function() { var members = [ { id: '1234', address: '1.2.3.4', subnet_id: 'subnet-1', protocol_port: 80, weight: 1 }, { id: '5678', address: '5.6.7.8', subnet_id: 'subnet-1', protocol_port: 80, weight: 1 }]; var deferred = $q.defer(); deferred.resolve({data: {items: members}}); return deferred.promise; }, getHealthMonitor: function() { var monitor = { id: '1234', type: 'HTTP', delay: 1, timeout: 1, max_retries: 1, max_retries_down: 1, http_method: 'POST', expected_codes: '200', url_path: '/test' }; var deferred = $q.defer(); deferred.resolve({data: monitor}); return deferred.promise; }, getFlavors: function() { var flavors = [{ name: 'flavor_1', id: 'f1' }, { name: 'flavor_2', id: 'f2' }]; var deferred = $q.defer(); deferred.resolve({data: {items: flavors}}); return deferred.promise; }, getAvailabilityZones: function() { var availabilityZones = [{ name: 'az_1', id: 'az1' }, { name: 'az_2', id: 'az2' }]; var deferred = $q.defer(); deferred.resolve({data: {items: availabilityZones}}); return deferred.promise; }, createLoadBalancer: function(spec) { return spec; }, editLoadBalancer: function(id, spec) { return spec; }, createListener: function(spec) { return spec; }, editListener: function(id, spec) { return spec; }, createL7Policy: function(spec) { return spec; }, editL7Policy: function(id, spec) { return spec; }, createL7Rule: function(l7policyId, spec) { return spec; }, editL7Rule: function(l7policyId, l7ruleId, spec) { return spec; }, createPool: function(spec) { return spec; }, editPool: function(id, spec) { return spec; }, createHealthMonitor: function(spec) { return spec; }, editHealthMonitor: function(id, spec) { return spec; }, updateMemberList: function(id, spec) { return spec; } }); $provide.value('horizon.app.core.openstack-service-api.octavia-barbican', { getCertificates: function() { var containers = [ { container_ref: 'container1', secret_refs: [{name: 'certificate', secret_ref: 'secret1'}] }, { container_ref: 'container2', secret_refs: [{name: 'certificate', secret_ref: 'certificate1'}, {name: 'private_key', secret_ref: 'privatekey1'}] }, { container_ref: 'container3', secret_refs: [{name: 'certificate', secret_ref: 'certificate2'}, {name: 'private_key', secret_ref: 'privatekey2'}] } ]; var deferred = $q.defer(); if (certificatesError) { deferred.reject(); } else { deferred.resolve({data: {items: containers}}); } return deferred.promise; }, getSecrets: function() { var secrets = [ { name: 'foo', expiration: '2016-03-26T21:10:45.417835', secret_ref: 'certificate1' }, { expiration: '2016-03-28T21:10:45.417835', secret_ref: 'certificate2', secret_type: 'opaque' }, { secret_ref: 'privatekey1' }, { secret_ref: 'privatekey2' }, { secret_ref: 'pkcs12', secret_type: 'opaque' } ]; var deferred = $q.defer(); deferred.resolve({data: {items: secrets}}); return deferred.promise; } }); $provide.value('horizon.app.core.openstack-service-api.neutron', { getSubnets: function() { var subnets = [{id: 'subnet-1', name: 'subnet-1'}, {id: 'subnet-2', name: 'subnet-2'}]; var deferred = $q.defer(); deferred.resolve({data: {items: subnets}}); return deferred.promise; }, getPorts: function() { var ports = [{ device_id: '1', fixed_ips: [{ip_address: '1.2.3.4', subnet_id: '1'}, {ip_address: '2.3.4.5', subnet_id: '2'}] }, { device_id: '2', fixed_ips: [{ip_address: '3.4.5.6', subnet_id: '1'}, {ip_address: '4.5.6.7', subnet_id: '2'}] }]; var deferred = $q.defer(); deferred.resolve({data: {items: ports}}); return deferred.promise; }, getNetworks: function() { var networks = [{ name: 'network_1', id: 'a1' }, { name: 'network_2', id: 'b2' }]; var deferred = $q.defer(); deferred.resolve({data: {items: networks}}); return deferred.promise; } }); $provide.value('horizon.app.core.openstack-service-api.nova', { getServers: function() { var servers = [{id: '1', name: 'server-1', addresses: {foo: 'bar'}}, {id: '2', name: 'server-2', addresses: {foo: 'bar'}}, {id: '3', name: 'server-3'}]; var deferred = $q.defer(); deferred.resolve({data: {items: servers}}); return deferred.promise; } }); $provide.value('horizon.app.core.openstack-service-api.serviceCatalog', { ifTypeEnabled: function() { var deferred = $q.defer(); deferred[barbicanEnabled ? 'resolve' : 'reject'](); return deferred.promise; } }); })); beforeEach(inject(function($injector) { model = $injector.get( 'horizon.dashboard.project.lbaasv2.workflow.model' ); $q = $injector.get('$q'); scope = $injector.get('$rootScope').$new(); })); describe('Initial model (pre-initialize)', function() { it('is defined', function() { expect(model).toBeDefined(); }); it('has initialization status parameters', function() { expect(model.initializing).toBeDefined(); expect(model.initialized).toBeDefined(); }); it('does not yet have a spec', function() { expect(model.spec).toBeNull(); }); it('has empty subnets array', function() { expect(model.subnets).toEqual([]); }); it('has empty networks', function() { expect(model.networks).toEqual({}); }); it('has empty members array', function() { expect(model.members).toEqual([]); }); it('has empty certificates array', function() { expect(model.certificates).toEqual([]); }); it('has empty listener protocol_ports array', function() { expect(model.listenerPorts).toEqual([]); }); it('has array of listener protocols', function() { expect(model.listenerProtocols).toEqual(['HTTP', 'TCP', 'TERMINATED_HTTPS', 'HTTPS', 'UDP', 'SCTP']); }); it('has array of pool lb_algorithms', function() { expect(model.methods).toEqual(['LEAST_CONNECTIONS', 'ROUND_ROBIN', 'SOURCE_IP']); }); it('has array of pool session persistence types', function() { expect(model.types).toEqual(['SOURCE_IP', 'HTTP_COOKIE', 'APP_COOKIE']); }); it('has array of monitor types', function() { expect(model.monitorTypes).toEqual(['HTTP', 'HTTPS', 'PING', 'TCP', 'TLS-HELLO', 'UDP-CONNECT', 'SCTP']); }); it('has array of monitor http_methods', function() { expect(model.monitorMethods).toEqual(['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'PATCH', 'CONNECT']); }); it('has an "initialize" function', function() { expect(model.initialize).toBeDefined(); }); it('has a "submit" function', function() { expect(model.submit).toBeDefined(); }); it('has a "context" object', function() { expect(model.context).toBeDefined(); }); }); describe('Post initialize model (create loadbalancer)', function() { beforeEach(function() { model.initialize('loadbalancer'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(2); expect(model.networks).toEqual(mockNetworks); expect(model.flavors).toEqual(mockFlavors); expect(model.availability_zones).toEqual(mockAvailabilityZones); expect(model.members.length).toBe(2); expect(model.certificates.length).toBe(3); expect(model.listenerPorts.length).toBe(0); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBeUndefined(); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.spec.members).toEqual([]); expect(model.spec.certificates).toEqual([]); expect(model.spec.monitor).toBeDefined(); expect(model.certificatesError).toBe(false); }); it('should initialize names', function() { expect(model.spec.loadbalancer.name).toBeNull(); expect(model.spec.listener.name).toBeNull(); expect(model.spec.pool.name).toBeNull(); }); it('should initialize context properties', function() { expect(model.context.resource).toBe('loadbalancer'); expect(model.context.id).toBeUndefined(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (create listener)', function() { beforeEach(function() { model.initialize('listener', false, '1234'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(2); expect(model.members.length).toBe(2); expect(model.certificates.length).toBe(3); expect(model.listenerPorts.length).toBe(3); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBe('1234'); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.spec.members).toEqual([]); expect(model.spec.certificates).toEqual([]); expect(model.spec.monitor).toBeDefined(); expect(model.certificatesError).toBe(false); }); it('should initialize names', function() { expect(model.spec.listener.name).toBeNull(); expect(model.spec.pool.name).toBeNull(); }); it('should initialize context properties', function() { expect(model.context.resource).toBe('listener'); expect(model.context.id).toBeFalsy(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (create l7 policy)', function() { beforeEach(function() { includeChildResources = false; model.initialize('l7policy', false, '1234', '5678'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(0); expect(model.members.length).toBe(0); expect(model.certificates.length).toBe(0); expect(model.listenerPorts.length).toBe(0); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBe('1234'); expect(model.spec.parentResourceId).toBe('5678'); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.spec.members.length).toBe(0); expect(model.spec.certificates).toEqual([]); expect(model.spec.monitor).toBeDefined(); expect(model.certificatesError).toBe(false); }); it('should initialize names', function() { expect(model.spec.l7policy.name).toBeNull(); }); it('should initialize context properties', function() { expect(model.context.resource).toBe('l7policy'); expect(model.context.id).toBeFalsy(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (create l7 rule)', function() { beforeEach(function() { includeChildResources = false; model.initialize('l7rule', false, '1234', '5678'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(0); expect(model.members.length).toBe(0); expect(model.certificates.length).toBe(0); expect(model.listenerPorts.length).toBe(0); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBe('1234'); expect(model.spec.parentResourceId).toBe('5678'); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.spec.members.length).toBe(0); expect(model.spec.certificates).toEqual([]); expect(model.spec.monitor).toBeDefined(); expect(model.certificatesError).toBe(false); }); it('should initialize invert', function() { expect(model.spec.l7rule.invert).toBe(false); }); it('should initialize context properties', function() { expect(model.context.resource).toBe('l7rule'); expect(model.context.id).toBeFalsy(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (create pool with listener)', function() { beforeEach(function() { includeChildResources = false; model.initialize('pool', false, '1234', '5678'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(2); expect(model.members.length).toBe(2); expect(model.certificates.length).toBe(0); expect(model.listenerPorts.length).toBe(0); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBe('1234'); expect(model.spec.parentResourceId).toBe('5678'); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.spec.members.length).toBe(0); expect(model.spec.certificates).toEqual([]); expect(model.spec.monitor).toBeDefined(); expect(model.certificatesError).toBe(false); }); it('should initialize names', function() { expect(model.spec.pool.name).toBeNull(); }); it('should initialize context properties', function() { expect(model.context.resource).toBe('pool'); expect(model.context.id).toBeFalsy(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (create pool without listener)', function() { beforeEach(function() { includeChildResources = false; model.initialize('pool', false, '1234'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(2); expect(model.members.length).toBe(2); expect(model.certificates.length).toBe(0); expect(model.listenerPorts.length).toBe(0); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBe('1234'); expect(model.spec.parentResourceId).toBeUndefined(); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.spec.members.length).toBe(0); expect(model.spec.certificates).toEqual([]); expect(model.spec.monitor).toBeDefined(); expect(model.certificatesError).toBe(false); }); it('should initialize names', function() { expect(model.spec.pool.name).toBeNull(); }); it('should initialize context properties', function() { expect(model.context.resource).toBe('pool'); expect(model.context.id).toBeFalsy(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (create health monitor)', function() { beforeEach(function() { model.initialize('monitor', null, 'loadbalancer1', 'pool1'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(0); expect(model.members.length).toBe(0); expect(model.certificates.length).toBe(0); expect(model.listenerPorts.length).toBe(0); expect(model.spec.loadbalancer_id).toBe('loadbalancer1'); expect(model.spec.parentResourceId).toBe('pool1'); expect(model.spec.members.length).toBe(0); expect(model.spec.certificates).toEqual([]); expect(model.certificatesError).toBe(false); }); it('should initialize context properties', function() { expect(model.context.resource).toBe('monitor'); expect(model.context.id).toBeFalsy(); expect(model.context.submit.name).toBe('createHealthMonitor'); }); }); describe('Post initialize model (edit loadbalancer)', function() { beforeEach(function() { model.initialize('loadbalancer', '1234'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(2); expect(model.networks).toEqual(mockNetworks); expect(model.flavors).toEqual(mockFlavors); expect(model.availability_zones).toEqual(mockAvailabilityZones); expect(model.members.length).toBe(0); expect(model.certificates.length).toBe(0); expect(model.listenerPorts.length).toBe(0); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBeUndefined(); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.spec.members).toEqual([]); expect(model.spec.certificates).toEqual([]); expect(model.spec.monitor).toBeDefined(); expect(model.certificatesError).toBe(false); }); it('should initialize loadbalancer model spec properties', function() { expect(model.spec.loadbalancer.name).toEqual('Load Balancer 1'); expect(model.spec.loadbalancer.description).toEqual(''); expect(model.spec.loadbalancer.vip_address).toEqual('1.2.3.4'); expect(model.spec.loadbalancer.vip_subnet_id).toEqual({ id: 'subnet-1', name: 'subnet-1' }); }); it('should not initialize listener model spec properties', function() { expect(model.spec.listener.id).toBeNull(); expect(model.spec.listener.name).toBeNull(); expect(model.spec.listener.description).toBeNull(); expect(model.spec.listener.protocol).toBeNull(); expect(model.spec.listener.protocol_port).toBeNull(); expect(model.spec.listener.connection_limit).toBe(-1); }); it('should not initialize pool model spec properties', function() { expect(model.spec.pool.id).toBeNull(); expect(model.spec.pool.name).toBeNull(); expect(model.spec.pool.description).toBeNull(); expect(model.spec.pool.protocol).toBeNull(); expect(model.spec.pool.lb_algorithm).toBeNull(); expect(model.spec.pool.session_persistence.type).toBeNull(); expect(model.spec.pool.session_persistence.cookie_name).toBeNull(); }); it('should initialize monitor model spec properties', function() { expect(model.spec.monitor.type).toBeNull(); expect(model.spec.monitor.delay).toBe(5); expect(model.spec.monitor.max_retries).toBe(3); expect(model.spec.monitor.max_retries_down).toBe(3); expect(model.spec.monitor.timeout).toBe(5); expect(model.spec.monitor.http_method).toBe('GET'); expect(model.spec.monitor.expected_codes).toBe('200'); expect(model.spec.monitor.url_path).toBe('/'); }); it('should not initialize any members in the model spec', function() { expect(model.spec.members).toEqual([]); }); it('should initialize context', function() { expect(model.context.resource).toBe('loadbalancer'); expect(model.context.id).toBe('1234'); expect(model.context.submit).toBeDefined(); }); it('should initialize listener protocols', function() { expect(model.listenerProtocols.length).toBe(6); expect(model.listenerProtocols.indexOf('TERMINATED_HTTPS')).toBe(2); }); }); describe('Post initialize model (edit health monitor)', function() { beforeEach(function() { model.initialize('monitor', 'healthmonitor1'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(0); expect(model.members.length).toBe(0); expect(model.certificates.length).toBe(0); expect(model.listenerPorts.length).toBe(0); expect(model.spec.loadbalancer_id).toBeUndefined(); expect(model.spec.parentResourceId).toBeUndefined(); expect(model.spec.members.length).toBe(0); expect(model.spec.certificates).toEqual([]); expect(model.certificatesError).toBe(false); expect(model.spec.monitor.id).toBe('1234'); expect(model.spec.monitor.type).toBe('HTTP'); expect(model.spec.monitor.delay).toBe(1); expect(model.spec.monitor.timeout).toBe(1); expect(model.spec.monitor.max_retries).toBe(1); expect(model.spec.monitor.max_retries_down).toBe(1); expect(model.spec.monitor.http_method).toBe('POST'); expect(model.spec.monitor.expected_codes).toBe('200'); expect(model.spec.monitor.url_path).toBe('/test'); }); it('should initialize context properties', function() { expect(model.context.resource).toBe('monitor'); expect(model.context.id).toBe('healthmonitor1'); expect(model.context.submit.name).toBe('editHealthMonitor'); }); }); describe('Post initialize model (without barbican)', function() { beforeEach(function() { barbicanEnabled = false; model.initialize('loadbalancer'); scope.$apply(); }); it('should initialize listener protocols', function() { expect(model.listenerProtocols.length).toBe(5); expect(model.listenerProtocols.indexOf('TERMINATED_HTTPS')).toBe(-1); }); }); describe('Post initialize model (certificates error)', function() { beforeEach(function() { certificatesError = true; model.initialize('loadbalancer'); scope.$apply(); }); it('should initialize listener protocols', function() { expect(model.certificates).toEqual([]); expect(model.certificatesError).toBe(true); }); }); describe('Post initialize model (edit listener)', function() { beforeEach(function() { includeChildResources = true; model.initialize('listener', '1234'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(2); expect(model.members.length).toEqual(2); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBeDefined(); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.subnets.length).toBe(2); expect(model.spec.monitor).toBeDefined(); }); it('should initialize the loadbalancer_id property', function() { expect(model.spec.loadbalancer_id).toBe('1234'); }); it('should initialize all loadbalancer properties to null', function() { expect(model.spec.loadbalancer.name).toBeNull(); expect(model.spec.loadbalancer.description).toBeNull(); expect(model.spec.loadbalancer.vip_address).toBeNull(); expect(model.spec.loadbalancer.vip_subnet_id).toBeNull(); }); it('should initialize all listener properties', function() { expect(model.spec.listener.id).toBe('1234'); expect(model.spec.listener.name).toBe('Listener 1'); expect(model.spec.listener.description).toBe('listener description'); expect(model.spec.listener.protocol).toBe('HTTP'); expect(model.spec.listener.protocol_port).toBe(80); expect(model.spec.listener.connection_limit).toBe(999); }); it('should initialize all pool properties', function() { expect(model.spec.pool.id).toBe('1234'); expect(model.spec.pool.name).toBe('Pool 1'); expect(model.spec.pool.description).toBe('pool description'); expect(model.spec.pool.protocol).toBe('HTTP'); expect(model.spec.pool.lb_algorithm).toBe('ROUND_ROBIN'); expect(model.spec.pool.session_persistence.type).toBe('APP_COOKIE'); expect(model.spec.pool.session_persistence.cookie_name).toBe('cookie_name'); }); it('should initialize all monitor properties', function() { expect(model.spec.monitor.id).toBe('1234'); expect(model.spec.monitor.type).toBe('HTTP'); expect(model.spec.monitor.delay).toBe(1); expect(model.spec.monitor.max_retries).toBe(1); expect(model.spec.monitor.max_retries_down).toBe(1); expect(model.spec.monitor.timeout).toBe(1); expect(model.spec.monitor.http_method).toBe('POST'); expect(model.spec.monitor.expected_codes).toBe('200'); expect(model.spec.monitor.url_path).toBe('/test'); }); it('should initialize members and properties', function() { expect(model.spec.members[0].id).toBe('1234'); expect(model.spec.members[0].address).toBe('1.2.3.4'); expect(model.spec.members[0].subnet_id).toEqual({ id: 'subnet-1', name: 'subnet-1' }); expect(model.spec.members[0].protocol_port).toBe(80); expect(model.spec.members[0].weight).toBe(1); expect(model.spec.members[1].id).toBe('5678'); expect(model.spec.members[1].address).toBe('5.6.7.8'); expect(model.spec.members[1].subnet_id).toEqual({ id: 'subnet-1', name: 'subnet-1' }); expect(model.spec.members[1].protocol_port).toBe(80); expect(model.spec.members[1].weight).toBe(1); }); it('should initialize context', function() { expect(model.context.resource).toBe('listener'); expect(model.context.id).toBeDefined(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (edit listener) no pool children', function() { beforeEach(function() { includeChildResources = true; delete listenerResources.members; delete listenerResources.monitor; model.initialize('listener', '1234'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(2); expect(model.members.length).toEqual(2); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBeDefined(); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.subnets.length).toBe(2); expect(model.spec.monitor).toBeDefined(); }); it('should initialize the loadbalancer_id property', function() { expect(model.spec.loadbalancer_id).toBe('1234'); }); it('should initialize all loadbalancer properties to null', function() { expect(model.spec.loadbalancer.name).toBeNull(); expect(model.spec.loadbalancer.description).toBeNull(); expect(model.spec.loadbalancer.vip_address).toBeNull(); expect(model.spec.loadbalancer.vip_subnet_id).toBeNull(); }); it('should initialize all listener properties', function() { expect(model.spec.listener.id).toBe('1234'); expect(model.spec.listener.name).toBe('Listener 1'); expect(model.spec.listener.description).toBe('listener description'); expect(model.spec.listener.protocol).toBe('HTTP'); expect(model.spec.listener.protocol_port).toBe(80); expect(model.spec.listener.connection_limit).toBe(999); }); it('should initialize all pool properties', function() { expect(model.spec.pool.id).toBe('1234'); expect(model.spec.pool.name).toBe('Pool 1'); expect(model.spec.pool.description).toBe('pool description'); expect(model.spec.pool.protocol).toBe('HTTP'); expect(model.spec.pool.lb_algorithm).toBe('ROUND_ROBIN'); expect(model.spec.pool.session_persistence.type).toBe('APP_COOKIE'); expect(model.spec.pool.session_persistence.cookie_name).toBe('cookie_name'); }); it('should initialize context', function() { expect(model.context.resource).toBe('listener'); expect(model.context.id).toBeDefined(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (edit l7 policy)', function() { beforeEach(function() { model.initialize('l7policy', '1234', 'loadbalancerId', 'listenerId'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBeDefined(); expect(model.spec.l7policy.id).toBe('1234'); expect(model.spec.l7policy.name).toBe('L7 Policy 1'); expect(model.spec.l7policy.description).toBe('l7 policy description'); }); it('should initialize context', function() { expect(model.context.resource).toBe('l7policy'); expect(model.context.id).toBeDefined(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (edit l7 rule)', function() { beforeEach(function() { model.initialize('l7rule', '1234', 'loadbalancerId', 'l7policyId'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBeDefined(); expect(model.spec.l7rule.id).toBe('1234'); expect(model.spec.l7rule.type).toBe('HOST_NAME'); }); it('should initialize context', function() { expect(model.context.resource).toBe('l7rule'); expect(model.context.id).toBeDefined(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (edit pool)', function() { beforeEach(function() { includeChildResources = true; model.initialize('pool', '1234', 'loadbalancerId'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(2); expect(model.members.length).toEqual(2); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBeDefined(); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.subnets.length).toBe(2); expect(model.spec.monitor).toBeDefined(); }); it('should initialize the loadbalancer_id property', function() { expect(model.spec.loadbalancer_id).toBe('loadbalancerId'); }); it('should initialize all loadbalancer properties to null', function() { expect(model.spec.loadbalancer.name).toBeNull(); expect(model.spec.loadbalancer.description).toBeNull(); expect(model.spec.loadbalancer.vip_address).toBeNull(); expect(model.spec.loadbalancer.vip_subnet_id).toBeNull(); }); it('should initialize all listener properties to null', function() { expect(model.spec.listener.id).toBeNull(); expect(model.spec.listener.name).toBeNull(); expect(model.spec.listener.description).toBeNull(); expect(model.spec.listener.protocol).toBeNull(); expect(model.spec.listener.protocol_port).toBeNull(); expect(model.spec.listener.connection_limit).toBe(-1); }); it('should initialize all pool properties', function() { expect(model.spec.pool.id).toBe('1234'); expect(model.spec.pool.name).toBe('Pool 1'); expect(model.spec.pool.description).toBe('pool description'); expect(model.spec.pool.protocol).toBe('HTTP'); expect(model.spec.pool.lb_algorithm).toBe('ROUND_ROBIN'); expect(model.spec.pool.session_persistence.type).toBe('APP_COOKIE'); expect(model.spec.pool.session_persistence.cookie_name).toBe('cookie_name'); }); it('should initialize all monitor properties', function() { expect(model.spec.monitor.id).toBe('1234'); expect(model.spec.monitor.type).toBe('HTTP'); expect(model.spec.monitor.delay).toBe(1); expect(model.spec.monitor.max_retries).toBe(1); expect(model.spec.monitor.max_retries_down).toBe(1); expect(model.spec.monitor.timeout).toBe(1); expect(model.spec.monitor.http_method).toBe('POST'); expect(model.spec.monitor.expected_codes).toBe('200'); expect(model.spec.monitor.url_path).toBe('/test'); }); it('should initialize members and properties', function() { expect(model.spec.members[0].id).toBe('1234'); expect(model.spec.members[0].address).toBe('1.2.3.4'); expect(model.spec.members[0].subnet_id).toEqual({ id: 'subnet-1', name: 'subnet-1' }); expect(model.spec.members[0].protocol_port).toBe(80); expect(model.spec.members[0].weight).toBe(1); expect(model.spec.members[1].id).toBe('5678'); expect(model.spec.members[1].address).toBe('5.6.7.8'); expect(model.spec.members[1].subnet_id).toEqual({ id: 'subnet-1', name: 'subnet-1' }); expect(model.spec.members[1].protocol_port).toBe(80); expect(model.spec.members[1].weight).toBe(1); }); it('should initialize context', function() { expect(model.context.resource).toBe('pool'); expect(model.context.id).toBeDefined(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (update member list)', function() { beforeEach(function() { includeChildResources = false; model.initialize('members', false, 'loadbalancerId', 'poolId'); scope.$apply(); }); it('should initialize model properties', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(true); expect(model.subnets.length).toBe(2); expect(model.members.length).toEqual(2); expect(model.spec).toBeDefined(); expect(model.spec.loadbalancer_id).toBeDefined(); expect(model.spec.loadbalancer).toBeDefined(); expect(model.spec.listener).toBeDefined(); expect(model.spec.pool).toBeDefined(); expect(model.subnets.length).toBe(2); expect(model.spec.monitor).toBeDefined(); }); it('should initialize the loadbalancer_id property', function() { expect(model.spec.loadbalancer_id).toBe('loadbalancerId'); }); it('should initialize all loadbalancer properties to null', function() { expect(model.spec.loadbalancer.name).toBeNull(); expect(model.spec.loadbalancer.description).toBeNull(); expect(model.spec.loadbalancer.vip_address).toBeNull(); expect(model.spec.loadbalancer.vip_subnet_id).toBeNull(); }); it('should initialize all listener properties to null', function() { expect(model.spec.listener.id).toBeNull(); expect(model.spec.listener.name).toBeNull(); expect(model.spec.listener.description).toBeNull(); expect(model.spec.listener.protocol).toBeNull(); expect(model.spec.listener.protocol_port).toBeNull(); expect(model.spec.listener.connection_limit).toBe(-1); }); it('should initialize all pool properties', function() { expect(model.spec.pool.id).toBe('1234'); expect(model.spec.pool.name).toBe('Pool 1'); expect(model.spec.pool.description).toBe('pool description'); expect(model.spec.pool.protocol).toBe('HTTP'); expect(model.spec.pool.lb_algorithm).toBe('ROUND_ROBIN'); expect(model.spec.pool.session_persistence.type).toBe('APP_COOKIE'); expect(model.spec.pool.session_persistence.cookie_name).toBe('cookie_name'); }); it('should initialize all monitor properties to null', function() { expect(model.spec.monitor.id).toBeNull(); expect(model.spec.monitor.type).toBeNull(); expect(model.spec.monitor.delay).toBe(5); expect(model.spec.monitor.max_retries).toBe(3); expect(model.spec.monitor.max_retries_down).toBe(3); expect(model.spec.monitor.timeout).toBe(5); expect(model.spec.monitor.http_method).toBe('GET'); expect(model.spec.monitor.expected_codes).toBe('200'); expect(model.spec.monitor.url_path).toBe('/'); }); it('should initialize members and properties', function() { expect(model.spec.members[0].id).toBe('1234'); expect(model.spec.members[0].address).toBe('1.2.3.4'); expect(model.spec.members[0].subnet_id).toEqual({ id: 'subnet-1', name: 'subnet-1' }); expect(model.spec.members[0].protocol_port).toBe(80); expect(model.spec.members[0].weight).toBe(1); expect(model.spec.members[1].id).toBe('5678'); expect(model.spec.members[1].address).toBe('5.6.7.8'); expect(model.spec.members[1].subnet_id).toEqual({ id: 'subnet-1', name: 'subnet-1' }); expect(model.spec.members[1].protocol_port).toBe(80); expect(model.spec.members[1].weight).toBe(1); }); it('should initialize context', function() { expect(model.context.resource).toBe('members'); expect(model.context.id).toBeFalsy(); expect(model.context.submit).toBeDefined(); }); }); describe('Post initialize model (edit listener TERMINATED_HTTPS)', function() { beforeEach(function() { includeChildResources = true; listenerResources.listener.protocol = 'TERMINATED_HTTPS'; model.initialize('listener', '1234'); scope.$apply(); }); it('should initialize certificates', function() { expect(model.certificates.length).toBe(3); expect(model.spec.certificates.length).toBe(1); expect(model.spec.certificates[0].id).toBe('container2'); }); }); describe('Post initialize model (edit listener TERMINATED_HTTPS no barbican)', function() { beforeEach(function() { listenerResources.listener.protocol = 'TERMINATED_HTTPS'; barbicanEnabled = false; model.initialize('listener', '1234'); scope.$apply(); }); it('should initialize certificates', function() { expect(model.certificates.length).toBe(0); expect(model.spec.certificates.length).toBe(0); expect(model.spec.listener.protocol).toBe('TERMINATED_HTTPS'); }); }); describe('Post initialize model - Initializing', function() { beforeEach(function() { model.initializing = true; model.initialize('loadbalancer'); scope.$apply(); }); // This is here to ensure that as people add/change spec properties, they don't forget // to implement tests for them. it('has the right number of properties', function() { expect(Object.keys(model.spec).length).toBe(11); expect(Object.keys(model.spec.loadbalancer).length).toBe(7); expect(Object.keys(model.spec.listener).length).toBe(16); expect(Object.keys(model.spec.l7policy).length).toBe(8); expect(Object.keys(model.spec.l7rule).length).toBe(7); expect(Object.keys(model.spec.pool).length).toBe(9); expect(Object.keys(model.spec.monitor).length).toBe(11); expect(model.spec.members).toEqual([]); }); it('sets load balancer ID to undefined', function() { expect(model.spec.loadbalancer_id).toBeUndefined(); }); it('sets parent resource ID to undefined', function() { expect(model.spec.parentResourceId).toBeUndefined(); }); it('sets load balancer name to null', function() { expect(model.spec.loadbalancer.name).toBeNull(); }); it('sets load balancer description to null', function() { expect(model.spec.loadbalancer.description).toBeNull(); }); it('sets load balancer ip address to null', function() { expect(model.spec.loadbalancer.vip_address).toBeNull(); }); it('sets load balancer subnet to null', function() { expect(model.spec.loadbalancer.vip_subnet_id).toBeNull(); }); it('sets listener id to null', function() { expect(model.spec.listener.id).toBeNull(); }); it('sets listener name to reasonable default', function() { expect(model.spec.listener.name).toBeNull(); }); it('sets listener description to null', function() { expect(model.spec.listener.description).toBeNull(); }); it('sets listener protocol to null', function() { expect(model.spec.listener.protocol).toBeNull(); }); it('sets listener protocol_port to null', function() { expect(model.spec.listener.protocol_port).toBeNull(); }); it('sets listener connection limit to reasonable default', function() { expect(model.spec.listener.connection_limit).toBe(-1); }); it('sets pool id to null', function() { expect(model.spec.pool.id).toBeNull(); }); it('sets pool name to reasonable default', function() { expect(model.spec.pool.name).toBeNull(); }); it('sets pool description to null', function() { expect(model.spec.pool.description).toBeNull(); }); it('sets pool protocol to null', function() { expect(model.spec.pool.protocol).toBeNull(); }); it('sets pool lb_algorithm to null', function() { expect(model.spec.pool.lb_algorithm).toBeNull(); }); it('sets monitor id to null', function() { expect(model.spec.monitor.id).toBeNull(); }); it('sets monitor type to null', function() { expect(model.spec.monitor.type).toBeNull(); }); it('sets monitor delay to 5', function() { expect(model.spec.monitor.delay).toBe(5); }); it('sets monitor max_retries count to 3', function() { expect(model.spec.monitor.max_retries).toBe(3); }); it('sets monitor max_retries down count to 3', function() { expect(model.spec.monitor.max_retries_down).toBe(3); }); it('sets monitor timeout to 5', function() { expect(model.spec.monitor.timeout).toBe(5); }); it('sets monitor http_method to default', function() { expect(model.spec.monitor.http_method).toBe('GET'); }); it('sets monitor expected_codes code to default', function() { expect(model.spec.monitor.expected_codes).toBe('200'); }); it('sets monitor URL path to default', function() { expect(model.spec.monitor.url_path).toBe('/'); }); }); describe('Initialization failure', function() { beforeEach(inject(function($injector) { var neutronAPI = $injector.get('horizon.app.core.openstack-service-api.neutron'); neutronAPI.getSubnets = function() { var deferred = $q.defer(); deferred.reject('Error'); return deferred.promise; }; })); beforeEach(function() { model.initialize('loadbalancer'); scope.$apply(); }); it('should fail to be initialized on subnets error', function() { expect(model.initializing).toBe(false); expect(model.initialized).toBe(false); expect(model.spec.loadbalancer.name).toBeNull(); expect(model.subnets).toEqual([]); }); }); describe('context (create loadbalancer)', function() { beforeEach(function() { model.initialize('loadbalancer'); scope.$apply(); }); it('should initialize context', function() { expect(model.context.resource).toBe('loadbalancer'); expect(model.context.id).toBeUndefined(); expect(model.context.submit.name).toBe('createLoadBalancer'); }); }); describe('context (edit loadbalancer)', function() { beforeEach(function() { model.initialize('loadbalancer', '1'); scope.$apply(); }); it('should initialize context', function() { expect(model.context.resource).toBe('loadbalancer'); expect(model.context.id).toBe('1'); expect(model.context.submit.name).toBe('editLoadBalancer'); }); }); describe('context (create listener)', function() { beforeEach(function() { model.initialize('listener', false, '1234'); scope.$apply(); }); it('should initialize context', function() { expect(model.context.resource).toBe('listener'); expect(model.context.id).toBeFalsy(); expect(model.context.submit.name).toBe('createListener'); }); }); describe('context (edit listener)', function() { beforeEach(function() { includeChildResources = true; model.initialize('listener', '1'); scope.$apply(); }); it('should initialize context', function() { expect(model.context.resource).toBe('listener'); expect(model.context.id).toBe('1'); expect(model.context.submit.name).toBe('editListener'); }); }); describe('context (create pool)', function() { beforeEach(function() { model.initialize('pool', false, '1234', '5678'); scope.$apply(); }); it('should initialize context', function() { expect(model.context.resource).toBe('pool'); expect(model.context.id).toBeFalsy(); expect(model.context.submit.name).toBe('createPool'); }); }); describe('context (edit pool)', function() { beforeEach(function() { includeChildResources = true; model.initialize('pool', 'poolId', 'loadbalancerId'); scope.$apply(); }); it('should initialize context', function() { expect(model.context.resource).toBe('pool'); expect(model.context.id).toBe('poolId'); expect(model.context.submit.name).toBe('editPool'); }); }); describe('context (update member list)', function() { beforeEach(function() { model.initialize('members', false, 'loadbalancerId', 'poolId'); scope.$apply(); }); it('should initialize context', function() { expect(model.context.resource).toBe('members'); expect(model.context.id).toBeFalsy(); expect(model.context.submit.name).toBe('updatePoolMemberList'); }); }); describe('Model submit function (create loadbalancer)', function() { beforeEach(function() { model.initialize('loadbalancer'); scope.$apply(); }); it('should set final spec properties', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.loadbalancer.flavor_id = model.flavors[Object.keys(model.flavors)[0]]; model.spec.loadbalancer.availability_zone = model.availability_zones[ Object.keys(model.availability_zones)[0]]; model.spec.listener.protocol = 'TCP'; model.spec.listener.protocol_port = 80; model.spec.listener.connection_limit = 999; model.spec.pool.name = 'pool name'; model.spec.pool.description = 'pool description'; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.pool.session_persistence.type = 'SOURCE_IP'; model.spec.members = [{ address: {ip: '1.2.3.4', subnet: '1'}, addresses: [{ip: '1.2.3.4', subnet: '1'}, {ip: '2.3.4.5', subnet: '2'}], id: '1', name: 'foo', protocol_port: 80, weight: 1 }, { id: 'external-member-0', address: '2.3.4.5', subnet_id: null, protocol_port: 80, weight: 1 }, { id: 'external-member-1', address: null, subnet_id: null, protocol_port: 80, weight: 1 }, { id: 'external-member-2', address: '3.4.5.6', subnet_id: {id: '1'}, protocol_port: 80, weight: 1 }]; model.spec.monitor.type = 'PING'; model.spec.monitor.delay = 1; model.spec.monitor.max_retries = 1; model.spec.monitor.max_retries_down = 1; model.spec.monitor.timeout = 1; model.spec.certificates = [{ id: 'container1', name: 'foo', expiration: '2015-03-26T21:10:45.417835' }]; var finalSpec = model.submit(); expect(finalSpec.loadbalancer.name).toBeUndefined(); expect(finalSpec.loadbalancer.description).toBeUndefined(); expect(finalSpec.loadbalancer.vip_address).toBe('1.2.3.4'); expect(finalSpec.loadbalancer.vip_subnet_id).toBe(model.subnets[0].id); expect(finalSpec.loadbalancer.admin_state_up).toBe(true); expect(finalSpec.loadbalancer.availability_zone).toBe('az_1'); expect(finalSpec.listener.name).toBeUndefined(); expect(finalSpec.listener.description).toBeUndefined(); expect(finalSpec.listener.protocol).toBe('TCP'); expect(finalSpec.listener.protocol_port).toBe(80); expect(finalSpec.listener.connection_limit).toBe(999); expect(finalSpec.listener.admin_state_up).toBe(true); expect(finalSpec.pool.name).toBe('pool name'); expect(finalSpec.pool.description).toBe('pool description'); expect(finalSpec.pool.protocol).toBe('TCP'); expect(finalSpec.pool.lb_algorithm).toBe('LEAST_CONNECTIONS'); expect(finalSpec.pool.session_persistence.type).toBe('SOURCE_IP'); expect(finalSpec.pool.admin_state_up).toBe(true); expect(finalSpec.members.length).toBe(3); expect(finalSpec.members[0].address).toBe('1.2.3.4'); expect(finalSpec.members[0].subnet_id).toBe('1'); expect(finalSpec.members[0].protocol_port).toBe(80); expect(finalSpec.members[0].weight).toBe(1); expect(finalSpec.members[0].id).toBe('1'); expect(finalSpec.members[0].addresses).toBeUndefined(); expect(finalSpec.members[0].name).toBe('foo'); expect(finalSpec.members[0].allocatedMember).toBeUndefined(); expect(finalSpec.members[1].id).toBe('external-member-0'); expect(finalSpec.members[1].address).toBe('2.3.4.5'); expect(finalSpec.members[1].subnet_id).toBeUndefined(); expect(finalSpec.members[1].protocol_port).toBe(80); expect(finalSpec.members[1].weight).toBe(1); expect(finalSpec.members[1].allocatedMember).toBeUndefined(); expect(finalSpec.members[2].id).toBe('external-member-2'); expect(finalSpec.members[2].address).toBe('3.4.5.6'); expect(finalSpec.members[2].subnet_id).toBe('1'); expect(finalSpec.members[2].protocol_port).toBe(80); expect(finalSpec.members[2].weight).toBe(1); expect(finalSpec.members[2].allocatedMember).toBeUndefined(); expect(finalSpec.monitor.type).toBe('PING'); expect(finalSpec.monitor.delay).toBe(1); expect(finalSpec.monitor.max_retries).toBe(1); expect(finalSpec.monitor.max_retries_down).toBe(1); expect(finalSpec.monitor.timeout).toBe(1); expect(finalSpec.certificates).toBeUndefined(); expect(finalSpec.monitor.admin_state_up).toBe(true); }); it('should set final spec certificates', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.loadbalancer.flavor_id = model.flavors[Object.keys(model.flavors)[0]]; model.spec.loadbalancer.availability_zone = model.availability_zones[ Object.keys(model.availability_zones)[0]]; model.spec.listener.protocol = 'TERMINATED_HTTPS'; model.spec.listener.protocol_port = 443; model.spec.listener.connection_limit = 9999; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.certificates = [{ id: 'container1', name: 'foo', expiration: '2015-03-26T21:10:45.417835' }]; var finalSpec = model.submit(); expect(finalSpec.loadbalancer.name).toBeUndefined(); expect(finalSpec.loadbalancer.description).toBeUndefined(); expect(finalSpec.loadbalancer.vip_address).toBe('1.2.3.4'); expect(finalSpec.loadbalancer.vip_subnet_id).toBe(model.subnets[0].id); expect(finalSpec.listener.name).toBeUndefined(); expect(finalSpec.listener.description).toBeUndefined(); expect(finalSpec.listener.protocol).toBe('TERMINATED_HTTPS'); expect(finalSpec.listener.protocol_port).toBe(443); expect(finalSpec.listener.connection_limit).toBe(9999); expect(finalSpec.pool.protocol).toBe('HTTP'); expect(finalSpec.certificates).toEqual(['container1']); }); it('should delete load balancer if any required property is not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeUndefined(); }); it('should delete listener if any required property is not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeUndefined(); expect(finalSpec.pool).toBeUndefined(); }); it('should delete certificates if not using TERMINATED_HTTPS', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.certificates = [{id: '1'}]; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.certificates).toBeUndefined(); }); it('should delete pool if any required property is not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeUndefined(); }); it('should delete members if none selected', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeDefined(); expect(finalSpec.members).toBeUndefined(); }); it('should delete members if no members are valid', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.members = [{ id: 'foo', address: '2.3.4.5', weight: 1 }]; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeDefined(); expect(finalSpec.members).toBeUndefined(); }); it('should delete monitor if any required property not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.monitor.type = 'PING'; model.spec.monitor.delay = 1; model.spec.monitor.max_retries = 1; model.spec.monitor.max_retries_down = 1; model.spec.monitor.timeout = null; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeDefined(); expect(finalSpec.members).toBeUndefined(); expect(finalSpec.monitor).toBeUndefined(); }); }); describe('Model submit function (edit loadbalancer)', function() { beforeEach(function() { model.initialize('loadbalancer', '1234'); scope.$apply(); }); it('should set final spec properties', function() { model.spec.loadbalancer.description = 'new description'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer.name).toBe('Load Balancer 1'); expect(finalSpec.loadbalancer.description).toBe('new description'); expect(finalSpec.loadbalancer.vip_address).toBe('1.2.3.4'); expect(finalSpec.loadbalancer.vip_subnet_id).toBe('subnet-1'); }); }); describe('Model submit function (create listener)', function() { beforeEach(function() { model.initialize('listener', false, '1234'); scope.$apply(); }); it('should set final spec properties', function() { model.spec.listener.protocol = 'TCP'; model.spec.listener.protocol_port = 80; model.spec.listener.connection_limit = 999; model.spec.pool.name = 'pool name'; model.spec.pool.description = 'pool description'; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.members = [{ address: {ip: '1.2.3.4', subnet: '1'}, addresses: [{ip: '1.2.3.4', subnet: '1'}, {ip: '2.3.4.5', subnet: '2'}], id: '1', name: 'foo', protocol_port: 80, weight: 1 }, { id: 'external-member-0', address: '2.3.4.5', subnet_id: null, protocol_port: 80, weight: 1 }, { id: 'external-member-1', address: null, subnet_id: null, protocol_port: 80, weight: 1 }, { id: 'external-member-2', address: '3.4.5.6', subnet_id: {id: '1'}, protocol_port: 80, weight: 1 }]; model.spec.monitor.type = 'PING'; model.spec.monitor.delay = 1; model.spec.monitor.max_retries = 1; model.spec.monitor.max_retries_down = 1; model.spec.monitor.timeout = 1; model.spec.certificates = [{ id: 'container1', name: 'foo', expiration: '2015-03-26T21:10:45.417835' }]; var finalSpec = model.submit(); expect(finalSpec.listener.name).toBeUndefined(); expect(finalSpec.listener.description).toBeUndefined(); expect(finalSpec.listener.protocol).toBe('TCP'); expect(finalSpec.listener.protocol_port).toBe(80); expect(finalSpec.listener.connection_limit).toBe(999); expect(finalSpec.pool.name).toBe('pool name'); expect(finalSpec.pool.description).toBe('pool description'); expect(finalSpec.pool.protocol).toBe('TCP'); expect(finalSpec.pool.lb_algorithm).toBe('LEAST_CONNECTIONS'); expect(finalSpec.members.length).toBe(3); expect(finalSpec.members[0].address).toBe('1.2.3.4'); expect(finalSpec.members[0].subnet_id).toBe('1'); expect(finalSpec.members[0].protocol_port).toBe(80); expect(finalSpec.members[0].weight).toBe(1); expect(finalSpec.members[0].id).toBe('1'); expect(finalSpec.members[0].addresses).toBeUndefined(); expect(finalSpec.members[0].name).toBe('foo'); expect(finalSpec.members[0].allocatedMember).toBeUndefined(); expect(finalSpec.members[1].id).toBe('external-member-0'); expect(finalSpec.members[1].address).toBe('2.3.4.5'); expect(finalSpec.members[1].subnet_id).toBeUndefined(); expect(finalSpec.members[1].protocol_port).toBe(80); expect(finalSpec.members[1].weight).toBe(1); expect(finalSpec.members[1].allocatedMember).toBeUndefined(); expect(finalSpec.members[2].id).toBe('external-member-2'); expect(finalSpec.members[2].address).toBe('3.4.5.6'); expect(finalSpec.members[2].subnet_id).toBe('1'); expect(finalSpec.members[2].protocol_port).toBe(80); expect(finalSpec.members[2].weight).toBe(1); expect(finalSpec.members[2].allocatedMember).toBeUndefined(); expect(finalSpec.monitor.type).toBe('PING'); expect(finalSpec.monitor.delay).toBe(1); expect(finalSpec.monitor.max_retries).toBe(1); expect(finalSpec.monitor.max_retries_down).toBe(1); expect(finalSpec.monitor.timeout).toBe(1); expect(finalSpec.certificates).toBeUndefined(); }); it('should set final spec certificates', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'TERMINATED_HTTPS'; model.spec.listener.protocol_port = 443; model.spec.listener.connection_limit = 999; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.certificates = [{ id: 'container1', name: 'foo', expiration: '2015-03-26T21:10:45.417835' }]; var finalSpec = model.submit(); expect(finalSpec.listener.name).toBeUndefined(); expect(finalSpec.listener.description).toBeUndefined(); expect(finalSpec.listener.protocol).toBe('TERMINATED_HTTPS'); expect(finalSpec.listener.protocol_port).toBe(443); expect(finalSpec.listener.connection_limit).toBe(999); expect(finalSpec.pool.protocol).toBe('HTTP'); expect(finalSpec.certificates).toEqual(['container1']); }); it('should delete listener if any required property is not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeUndefined(); expect(finalSpec.pool).toBeUndefined(); }); it('should delete certificates if not using TERMINATED_HTTPS', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.certificates = [{id: '1'}]; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.certificates).toBeUndefined(); }); it('should delete pool if any required property is not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeUndefined(); }); it('should delete members if none selected', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeDefined(); expect(finalSpec.members).toBeUndefined(); }); it('should delete members if no members are valid', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.members = [{ id: 'foo', address: '2.3.4.5', weight: 1 }]; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeDefined(); expect(finalSpec.members).toBeUndefined(); }); it('should delete monitor if any required property not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.monitor.type = 'PING'; model.spec.monitor.delay = 1; model.spec.monitor.max_retries = 1; model.spec.monitor.max_retries_down = 1; model.spec.monitor.timeout = null; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeDefined(); expect(finalSpec.members).toBeUndefined(); expect(finalSpec.monitor).toBeUndefined(); }); }); describe('Model submit function (create l7 policy)', function() { beforeEach(function() { model.initialize('l7policy', null, '1234', 'listener1'); scope.$apply(); }); it('should set final spec properties', function() { model.spec.l7policy.action = 'REJECT'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer_id).toBe('1234'); expect(finalSpec.parentResourceId).toBe('listener1'); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.l7policy.action).toBe('REJECT'); }); }); describe('Model submit function (create l7 rule)', function() { beforeEach(function() { model.initialize('l7rule', null, '1234', 'l7policy1'); scope.$apply(); }); it('should set final spec properties', function() { model.spec.l7rule.type = 'PATH'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer_id).toBe('1234'); expect(finalSpec.parentResourceId).toBe('l7policy1'); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.l7rule.type).toBe('PATH'); }); }); describe('Model submit function (create pool)', function() { beforeEach(function() { includeChildResources = false; model.initialize('pool', false, '1234', '5678'); scope.$apply(); }); it('should set final spec properties', function() { model.spec.listener.protocol = 'TCP'; model.spec.pool.name = 'pool name'; model.spec.pool.description = 'pool description'; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.members = [{ address: {ip: '1.2.3.4', subnet: '1'}, addresses: [{ip: '1.2.3.4', subnet: '1'}, {ip: '2.3.4.5', subnet: '2'}], id: '1', name: 'foo', protocol_port: 80, weight: 1 }, { id: 'external-member-0', address: '2.3.4.5', subnet_id: null, protocol_port: 80, weight: 1 }, { id: 'external-member-1', address: null, subnet_id: null, protocol_port: 80, weight: 1 }, { id: 'external-member-2', address: '3.4.5.6', subnet_id: {id: '1'}, protocol_port: 80, weight: 1 }]; model.spec.monitor.type = 'PING'; model.spec.monitor.delay = 1; model.spec.monitor.max_retries = 1; model.spec.monitor.max_retries_down = 1; model.spec.monitor.timeout = 1; model.spec.certificates = [{ id: 'container1', name: 'foo', expiration: '2015-03-26T21:10:45.417835' }]; var finalSpec = model.submit(); expect(finalSpec.pool.name).toBe('pool name'); expect(finalSpec.pool.description).toBe('pool description'); expect(finalSpec.pool.protocol).toBe('TCP'); expect(finalSpec.pool.lb_algorithm).toBe('LEAST_CONNECTIONS'); expect(finalSpec.members.length).toBe(3); expect(finalSpec.members[0].address).toBe('1.2.3.4'); expect(finalSpec.members[0].subnet_id).toBe('1'); expect(finalSpec.members[0].protocol_port).toBe(80); expect(finalSpec.members[0].weight).toBe(1); expect(finalSpec.members[0].id).toBe('1'); expect(finalSpec.members[0].addresses).toBeUndefined(); expect(finalSpec.members[0].name).toBe('foo'); expect(finalSpec.members[0].allocatedMember).toBeUndefined(); expect(finalSpec.members[1].id).toBe('external-member-0'); expect(finalSpec.members[1].address).toBe('2.3.4.5'); expect(finalSpec.members[1].subnet_id).toBeUndefined(); expect(finalSpec.members[1].protocol_port).toBe(80); expect(finalSpec.members[1].weight).toBe(1); expect(finalSpec.members[1].allocatedMember).toBeUndefined(); expect(finalSpec.members[2].id).toBe('external-member-2'); expect(finalSpec.members[2].address).toBe('3.4.5.6'); expect(finalSpec.members[2].subnet_id).toBe('1'); expect(finalSpec.members[2].protocol_port).toBe(80); expect(finalSpec.members[2].weight).toBe(1); expect(finalSpec.members[2].allocatedMember).toBeUndefined(); expect(finalSpec.monitor.type).toBe('PING'); expect(finalSpec.monitor.delay).toBe(1); expect(finalSpec.monitor.max_retries).toBe(1); expect(finalSpec.monitor.max_retries_down).toBe(1); expect(finalSpec.monitor.timeout).toBe(1); expect(finalSpec.certificates).toBeUndefined(); }); it('should delete listener if any required property is not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = ''; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeUndefined(); expect(finalSpec.pool).toBeUndefined(); }); it('should delete certificates if not using TERMINATED_HTTPS', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.certificates = [{id: '1'}]; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.certificates).toBeUndefined(); }); it('should delete pool if any required property is not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeUndefined(); }); it('should delete members if none selected', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeDefined(); expect(finalSpec.members).toBeUndefined(); }); it('should delete members if no members are valid', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.members = [{ id: 'foo', address: '2.3.4.5', weight: 1 }]; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeDefined(); expect(finalSpec.members).toBeUndefined(); }); it('should delete monitor if any required property not set', function() { model.spec.loadbalancer.vip_address = '1.2.3.4'; model.spec.loadbalancer.vip_subnet_id = model.subnets[0]; model.spec.listener.protocol = 'HTTP'; model.spec.listener.protocol_port = 80; model.spec.pool.lb_algorithm = 'LEAST_CONNECTIONS'; model.spec.monitor.type = 'PING'; model.spec.monitor.delay = 1; model.spec.monitor.max_retries = 1; model.spec.monitor.max_retries_down = 1; model.spec.monitor.timeout = null; var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeDefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.pool).toBeDefined(); expect(finalSpec.members).toBeUndefined(); expect(finalSpec.monitor).toBeUndefined(); }); }); describe('Model submit function (create health monitor)', function() { beforeEach(function() { model.initialize('monitor', null, 'loadbalancer1', 'pool1'); scope.$apply(); }); it('should set final spec properties', function() { model.spec.monitor.type = 'HTTP'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer_id).toBe('loadbalancer1'); expect(finalSpec.parentResourceId).toBe('pool1'); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.listener).toBeUndefined(); expect(finalSpec.pool).toBeUndefined(); expect(finalSpec.members).toBeUndefined(); expect(finalSpec.certificates).toBeUndefined(); expect(finalSpec.monitor.type).toBe('HTTP'); expect(finalSpec.monitor.delay).toBe(5); expect(finalSpec.monitor.max_retries).toBe(3); expect(finalSpec.monitor.max_retries_down).toBe(3); expect(finalSpec.monitor.timeout).toBe(5); expect(finalSpec.monitor.http_method).toBe('GET'); expect(finalSpec.monitor.expected_codes).toBe('200'); expect(finalSpec.monitor.url_path).toBe('/'); }); }); describe('Model submit function (edit listener)', function() { beforeEach(function() { includeChildResources = true; model.initialize('listener', '1234'); scope.$apply(); }); it('should set final spec properties', function() { var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.listener.name).toBe('Listener 1'); expect(finalSpec.listener.description).toBe('listener description'); expect(finalSpec.listener.protocol).toBe('HTTP'); expect(finalSpec.listener.protocol_port).toBe(80); expect(finalSpec.pool.name).toBe('Pool 1'); expect(finalSpec.pool.description).toBe('pool description'); expect(finalSpec.pool.protocol).toBe('HTTP'); expect(finalSpec.pool.lb_algorithm).toBe('ROUND_ROBIN'); expect(finalSpec.pool.session_persistence.type).toBe('APP_COOKIE'); expect(finalSpec.pool.session_persistence.cookie_name).toBe('cookie_name'); expect(finalSpec.members.length).toBe(2); expect(finalSpec.members[0].id).toBe('1234'); expect(finalSpec.members[0].address).toBe('1.2.3.4'); expect(finalSpec.members[0].subnet_id).toBe('subnet-1'); expect(finalSpec.members[0].protocol_port).toBe(80); expect(finalSpec.members[0].weight).toBe(1); expect(finalSpec.members[1].id).toBe('5678'); expect(finalSpec.members[1].address).toBe('5.6.7.8'); expect(finalSpec.members[1].subnet_id).toBe('subnet-1'); expect(finalSpec.members[1].protocol_port).toBe(80); expect(finalSpec.members[1].weight).toBe(1); expect(finalSpec.monitor.type).toBe('HTTP'); expect(finalSpec.monitor.delay).toBe(1); expect(finalSpec.monitor.max_retries).toBe(1); expect(finalSpec.monitor.max_retries_down).toBe(1); expect(finalSpec.monitor.timeout).toBe(1); }); }); describe('Model submit function (edit l7 policy)', function() { beforeEach(function() { model.initialize('l7policy', 'l7policy1', '1234', '1234'); scope.$apply(); }); it('should set final spec properties', function() { var finalSpec = model.submit(); expect(finalSpec.loadbalancer_id).toBe('1234'); expect(finalSpec.parentResourceId).toBe('1234'); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.listener).toBeDefined(); expect(finalSpec.l7policy.action).toBe('REDIRECT_TO_URL'); }); }); describe('Model submit function (edit l7 rule)', function() { beforeEach(function() { model.initialize('l7rule', '1234', '1234', '1234'); scope.$apply(); }); it('should set final spec properties', function() { var finalSpec = model.submit(); expect(finalSpec.loadbalancer_id).toBe('1234'); expect(finalSpec.parentResourceId).toBe('1234'); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.l7rule.type).toBe('HOST_NAME'); }); }); describe('Model submit function (edit pool)', function() { beforeEach(function() { includeChildResources = true; model.initialize('pool', 'poolId', 'loadbalancerId'); scope.$apply(); }); it('should set final spec properties', function() { var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.listener).toBeUndefined(); expect(finalSpec.pool.name).toBe('Pool 1'); expect(finalSpec.pool.description).toBe('pool description'); expect(finalSpec.pool.protocol).toBe('HTTP'); expect(finalSpec.pool.lb_algorithm).toBe('ROUND_ROBIN'); expect(finalSpec.pool.session_persistence.type).toBe('APP_COOKIE'); expect(finalSpec.pool.session_persistence.cookie_name).toBe('cookie_name'); expect(finalSpec.pool.tls_ciphers).toBeUndefined(); expect(finalSpec.members.length).toBe(2); expect(finalSpec.members[0].id).toBe('1234'); expect(finalSpec.members[0].address).toBe('1.2.3.4'); expect(finalSpec.members[0].subnet_id).toBe('subnet-1'); expect(finalSpec.members[0].protocol_port).toBe(80); expect(finalSpec.members[0].weight).toBe(1); expect(finalSpec.members[1].id).toBe('5678'); expect(finalSpec.members[1].address).toBe('5.6.7.8'); expect(finalSpec.members[1].subnet_id).toBe('subnet-1'); expect(finalSpec.members[1].protocol_port).toBe(80); expect(finalSpec.members[1].weight).toBe(1); expect(finalSpec.monitor.type).toBe('HTTP'); expect(finalSpec.monitor.delay).toBe(1); expect(finalSpec.monitor.max_retries).toBe(1); expect(finalSpec.monitor.max_retries_down).toBe(1); expect(finalSpec.monitor.timeout).toBe(1); }); }); describe('Model submit function (edit pool tls_enabled)', function() { beforeEach(function() { includeChildResources = true; listenerResources.pool.tls_enabled = true; listenerResources.pool.tls_ciphers = "A:B:C"; model.initialize('pool', 'poolId', 'loadbalancerId'); scope.$apply(); }); it('should set final spec properties', function() { var finalSpec = model.submit(); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.listener).toBeUndefined(); expect(finalSpec.pool.name).toBe('Pool 1'); expect(finalSpec.pool.description).toBe('pool description'); expect(finalSpec.pool.protocol).toBe('HTTP'); expect(finalSpec.pool.lb_algorithm).toBe('ROUND_ROBIN'); expect(finalSpec.pool.session_persistence.type).toBe('APP_COOKIE'); expect(finalSpec.pool.session_persistence.cookie_name).toBe('cookie_name'); expect(finalSpec.pool.tls_enabled).toBe(true); expect(finalSpec.pool.tls_ciphers).toBe("A:B:C"); expect(finalSpec.members.length).toBe(2); expect(finalSpec.members[0].id).toBe('1234'); expect(finalSpec.members[0].address).toBe('1.2.3.4'); expect(finalSpec.members[0].subnet_id).toBe('subnet-1'); expect(finalSpec.members[0].protocol_port).toBe(80); expect(finalSpec.members[0].weight).toBe(1); expect(finalSpec.members[1].id).toBe('5678'); expect(finalSpec.members[1].address).toBe('5.6.7.8'); expect(finalSpec.members[1].subnet_id).toBe('subnet-1'); expect(finalSpec.members[1].protocol_port).toBe(80); expect(finalSpec.members[1].weight).toBe(1); expect(finalSpec.monitor.type).toBe('HTTP'); expect(finalSpec.monitor.delay).toBe(1); expect(finalSpec.monitor.max_retries).toBe(1); expect(finalSpec.monitor.max_retries_down).toBe(1); expect(finalSpec.monitor.timeout).toBe(1); }); }); describe('Model submit function (update member list)', function() { beforeEach(function() { includeChildResources = false; model.initialize('members', false, 'loadbalancerId', 'poolId'); scope.$apply(); }); it('should set final spec properties', function() { var finalSpec = model.submit(); expect(finalSpec.loadbalancer_id).toBe('loadbalancerId'); expect(finalSpec.parentResourceId).toBe('poolId'); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.listener).toBeUndefined(); expect(finalSpec.pool.name).toBe('Pool 1'); expect(finalSpec.pool.description).toBe('pool description'); expect(finalSpec.pool.protocol).toBe('HTTP'); expect(finalSpec.pool.lb_algorithm).toBe('ROUND_ROBIN'); expect(finalSpec.pool.session_persistence.type).toBe('APP_COOKIE'); expect(finalSpec.pool.session_persistence.cookie_name).toBe('cookie_name'); expect(finalSpec.members.length).toBe(2); expect(finalSpec.members[0].id).toBe('1234'); expect(finalSpec.members[0].address).toBe('1.2.3.4'); expect(finalSpec.members[0].subnet_id).toBe('subnet-1'); expect(finalSpec.members[0].protocol_port).toBe(80); expect(finalSpec.members[0].weight).toBe(1); expect(finalSpec.members[1].id).toBe('5678'); expect(finalSpec.members[1].address).toBe('5.6.7.8'); expect(finalSpec.members[1].subnet_id).toBe('subnet-1'); expect(finalSpec.members[1].protocol_port).toBe(80); expect(finalSpec.members[1].weight).toBe(1); expect(finalSpec.monitor.delay).toBe(5); expect(finalSpec.monitor.max_retries).toBe(3); expect(finalSpec.monitor.max_retries_down).toBe(3); expect(finalSpec.monitor.timeout).toBe(5); }); }); describe('Model visible resources (edit pool, no pool in response)', function() { beforeEach(function() { includeChildResources = true; delete listenerResources.pool; model.initialize('pool', 'poolId', 'loadbalancerId'); scope.$apply(); }); it('should only show pool and monitor details', function() { expect(model.context.id).toEqual('poolId'); }); }); describe('Model visible resources (edit pool, no existing members)', function() { beforeEach(function() { includeChildResources = true; delete listenerResources.listener; delete listenerResources.members; model.initialize('pool', 'poolId', 'loadbalancerId'); scope.$apply(); }); it('should only show pool and monitor details', function() { expect(model.context.id).toEqual('poolId'); }); }); describe('Model visible resources (edit pool, no monitor)', function() { beforeEach(function() { includeChildResources = true; delete listenerResources.listener; delete listenerResources.monitor; model.initialize('pool', 'poolId', 'loadbalancerId'); scope.$apply(); }); it('should only show pool and monitor details', function() { expect(model.context.id).toEqual('poolId'); }); }); describe('Model visible resources (edit pool, no session persistence)', function() { beforeEach(function() { includeChildResources = true; delete listenerResources.listener; delete listenerResources.monitor; delete listenerResources.pool.session_persistence; model.initialize('pool', 'poolId', 'loadbalancerId'); scope.$apply(); }); it('should only show pool and monitor details', function() { model.submit(); expect(model.context.id).toEqual('poolId'); }); }); describe('Model visible resources (edit pool, no session persistence type)', function() { beforeEach(function() { includeChildResources = true; delete listenerResources.listener; delete listenerResources.monitor; delete listenerResources.pool.session_persistence.type; model.initialize('pool', 'poolId', 'loadbalancerId'); scope.$apply(); }); it('should only show pool and monitor details', function() { expect(model.context.id).toEqual('poolId'); }); }); describe('Model visible resources (edit pool, no session persistence cookie name)', function() { beforeEach(function() { includeChildResources = true; delete listenerResources.listener; delete listenerResources.monitor; delete listenerResources.pool.session_persistence.cookie_name; model.initialize('pool', 'poolId', 'loadbalancerId'); scope.$apply(); }); it('should only show pool and monitor details', function() { expect(model.context.id).toEqual('poolId'); }); }); describe('Model submit function (edit health monitor)', function() { beforeEach(function() { model.initialize('monitor', 'healthmonitor1'); scope.$apply(); }); it('should set final spec properties', function() { model.spec.monitor.delay = 10; model.spec.monitor.max_retries = 6; model.spec.monitor.max_retries_down = 6; model.spec.monitor.timeout = 8; model.spec.monitor.http_method = 'GET'; model.spec.monitor.expected_codes = '200-204'; model.spec.monitor.url_path = '/foo/bar'; var finalSpec = model.submit(); expect(finalSpec.loadbalancer_id).toBeUndefined(); expect(finalSpec.parentResourceId).toBeUndefined(); expect(finalSpec.loadbalancer).toBeUndefined(); expect(finalSpec.listener).toBeUndefined(); expect(finalSpec.pool).toBeUndefined(); expect(finalSpec.members).toBeUndefined(); expect(finalSpec.certificates).toBeUndefined(); expect(finalSpec.monitor.type).toBe('HTTP'); expect(finalSpec.monitor.delay).toBe(10); expect(finalSpec.monitor.max_retries).toBe(6); expect(finalSpec.monitor.max_retries_down).toBe(6); expect(finalSpec.monitor.timeout).toBe(8); expect(finalSpec.monitor.http_method).toBe('GET'); expect(finalSpec.monitor.expected_codes).toBe('200-204'); expect(finalSpec.monitor.url_path).toBe('/foo/bar'); }); }); describe('Model visible resources (edit listener, no insert headers)', function() { beforeEach(function() { delete listenerResources.listener.insert_headers; delete listenerResources.pool; model.initialize('listener', '1234'); scope.$apply(); }); it('should only show listener details', function() { expect(model.context.resource).toEqual('listener'); }); }); describe('Model visible resources (edit listener, no x forwared for)', function() { beforeEach(function() { listenerResources.listener.insert_headers['X-Forwarded-For'] = ''; delete listenerResources.pool; model.initialize('listener', '1234'); scope.$apply(); }); it('should only show listener details', function() { model.submit(); expect(model.context.resource).toEqual('listener'); }); }); describe('Model visible resources (edit listener, no x forwared port)', function() { beforeEach(function() { delete listenerResources.listener.insert_headers['X-Forwarded-Port']; delete listenerResources.pool; model.initialize('listener', '1234'); scope.$apply(); }); it('should only show listener details', function() { expect(model.context.resource).toEqual('listener'); }); }); describe('Model visible resources (edit listener, no x forwared proto)', function() { beforeEach(function() { delete listenerResources.listener.insert_headers['X-Forwarded-Proto']; delete listenerResources.pool; model.initialize('listener', '1234'); scope.$apply(); }); it('should only show listener details', function() { expect(model.context.resource).toEqual('listener'); }); }); describe('Model visible resources (edit listener, no pool)', function() { beforeEach(function() { delete listenerResources.pool; model.initialize('listener', '1234'); scope.$apply(); }); it('should only show listener details', function() { expect(model.context.resource).toEqual('listener'); }); }); describe('Model visible resources (edit listener, no monitor or existing members)', function() { beforeEach(function() { delete listenerResources.members; delete listenerResources.monitor; model.initialize('listener', '1234'); scope.$apply(); }); it('should only show listener, pool, and member details', function() { expect(model.context.resource).toEqual('listener'); }); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4731007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/0000775000175100017510000000000015033037476032426 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022700000000000010216 xustar00129 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/mo0000664000175100017510000000566515033037474032776 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .controller('MonitorDetailsController', MonitorDetailsController); MonitorDetailsController.$inject = [ '$scope', 'horizon.dashboard.project.lbaasv2.patterns', 'horizon.framework.widgets.wizard.events', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name MonitorDetailsController * @description * The `MonitorDetailsController` controller provides functions for * configuring the health monitor step of the LBaaS wizard. * @param $scope The angular scope object. * @param patterns The LBaaS v2 patterns constant. * @param wizardEvents The horizon wizard events. * @param gettext The horizon gettext function for translation. * @returns undefined */ function MonitorDetailsController($scope, patterns, wizardEvents, gettext) { var ctrl = this; $scope.$on(wizardEvents.ON_SWITCH, function(event, args) { var nextButtonSelector = "div.modal-footer button:nth-last-of-type(2)"; if (args.to === $scope.$index) { if ($scope.model.spec.listener.protocol !== 'TERMINATED_HTTPS') { $(nextButtonSelector).attr("disabled", ""); } } else { $(nextButtonSelector).removeAttr("disabled"); } }); ctrl.createChange = createChange; function createChange() { if ($scope.model.context.create_monitor) { // Enabling pool form enables listener form and pool form $scope.model.context.create_listener = true; $scope.model.context.create_pool = true; } } // Error text for invalid fields /* eslint-disable max-len */ ctrl.intervalError = gettext('The health check interval must be greater than or equal to the timeout.'); /* eslint-enable max-len */ ctrl.retryError = gettext('The max retry count must be a number between 1 and 10.'); ctrl.retryDownError = gettext('The max retry down count must be a number between 1 and 10.'); ctrl.timeoutError = gettext('The timeout must be a number greater than or equal to 0.'); ctrl.statusError = gettext('The expected status code is not valid.'); ctrl.pathError = gettext('The URL path is not valid.'); // HTTP status codes validation pattern ctrl.statusPattern = patterns.httpStatusCodes; ctrl.urlPathPattern = patterns.urlPath; } })(); ././@PaxHeader0000000000000000000000000000023400000000000010214 xustar00134 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/mo0000664000175100017510000000560715033037474032772 0ustar00mylesmyles/* * Copyright 2016 IBM Corp. * * 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. */ (function() { 'use strict'; describe('Monitor Details Step', function() { beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.dashboard.project.lbaasv2')); describe('MonitorDetailsController', function() { var ctrl, scope; beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); ctrl = $controller('MonitorDetailsController', { $scope: scope }); })); it('should define error messages for invalid fields', function() { expect(ctrl.intervalError).toBeDefined(); expect(ctrl.retryError).toBeDefined(); expect(ctrl.timeoutError).toBeDefined(); expect(ctrl.statusError).toBeDefined(); expect(ctrl.pathError).toBeDefined(); }); it('should define patterns for field validation', function() { expect(ctrl.statusPattern).toBeDefined(); expect(ctrl.urlPathPattern).toBeDefined(); }); it('should handle wizard event', function() { scope.$index = 2; scope.model = { spec: { listener: { protocol: 'TERMINATED_HTTPS' } } }; scope.$broadcast('ON_SWITCH', { from: 1, to: 2 }); scope.model = { spec: { listener: { protocol: 'HTTP' } } }; scope.$broadcast('ON_SWITCH', { from: 1, to: 2 }); scope.$broadcast('ON_SWITCH', { from: 2, to: 1 }); }); it('should update create_pool and create_monitor flags', function() { scope.model = { context: { create_listener: false, create_pool: false, create_monitor: true } }; ctrl.createChange(); expect(scope.model.context.create_listener).toBe(true); expect(scope.model.context.create_pool).toBe(true); scope.model = { context: { create_listener: false, create_pool: false, create_monitor: false } }; ctrl.createChange(); expect(scope.model.context.create_listener).toBe(false); expect(scope.model.context.create_pool).toBe(false); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022300000000000010212 xustar00125 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.help.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/mo0000664000175100017510000000315615033037474032767 0ustar00mylesmyles

The health monitor is used to determine the health of your pool members. Health checks routinely run against each member within the pool and the result of the health check is used to determine if the member receives new connections. Each pool can only have one health monitor.

Delay: The interval between health checks. Must be greater than or equal to the timeout.

Max Retries: The number of allowed connection failures before marking the member as inactive. Must be a number from 1 to 10.

Max Retries Down: The number of allowed connection failures before marking the member as error. Must be a number from 1 to 10. The default is 3.

Timeout: The time after which a health check times out. Must be a number greater than or equal to 0 and less than or equal to the interval.

HTTP Method: The HTTP method used to perform the health check.

Expected Codes: The expected HTTP status codes to get from a successful health check. Must be a single number, a comma separated list of numbers, or a range (two numbers separated by a hyphen).

URL Path: The target of the health check HTTP request to the member. Must be a valid URL path.

././@PaxHeader0000000000000000000000000000021600000000000010214 xustar00120 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/mo0000664000175100017510000001657015033037474032773 0ustar00mylesmyles

Provide the details for the health monitor.

{$ ::ctrl.retryDownError $}
{$ ::ctrl.intervalError $}
{$ ::ctrl.retryError $}
{$ ::ctrl.timeoutError $}
{$ ::ctrl.statusError $}
{$ ::ctrl.pathError $}
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4731007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/0000775000175100017510000000000015033037476031710 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000022100000000000010210 xustar00123 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.controller.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.0000664000175100017510000000334615033037474032666 0ustar00mylesmyles/* * Copyright 2020 Red Hat, Inc. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .controller('PoolDetailsController', PoolDetailsController); PoolDetailsController.$inject = [ '$scope', 'horizon.framework.util.i18n.gettext' ]; /** * @ngdoc controller * @name PoolDetailsController * @description * The `PoolDetailsController` controller provides functions for * configuring the pool details step of the LBaaS wizard. * @param $scope The angular scope object. * @param gettext The horizon gettext function for translation. * @returns undefined */ function PoolDetailsController($scope, gettext) { var ctrl = this; ctrl.createChange = createChange; function createChange() { if ($scope.model.context.create_pool) { // Enabling pool form enables listener form $scope.model.context.create_listener = true; } else { // Disabling pool form disables monitor form $scope.model.context.create_monitor = false; } } // Error text for invalid fields ctrl.tls_ciphersError = gettext('The cipher string must conform to OpenSSL syntax.'); } })(); ././@PaxHeader0000000000000000000000000000022600000000000010215 xustar00128 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.controller.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.0000664000175100017510000000352415033037474032664 0ustar00mylesmyles/* * Copyright 2020 Red Hat, Inc. * * 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. */ (function() { 'use strict'; describe('Pool Details Step', function() { beforeEach(module('horizon.framework.util.i18n')); beforeEach(module('horizon.dashboard.project.lbaasv2')); describe('PoolDetailsController', function() { var ctrl, scope; beforeEach(inject(function($controller) { scope = { model: { context: { create_listener: true, create_pool: true, create_monitor: true } } }; ctrl = $controller('PoolDetailsController', { $scope: scope }); })); it('should define error messages for invalid fields', function() { expect(ctrl.tls_ciphersError).toBeDefined(); }); it('should update create_listener and create_monitor flags', function() { scope.model.context.create_pool = true; ctrl.createChange(); expect(scope.model.context.create_listener).toBe(true); expect(scope.model.context.create_monitor).toBe(true); scope.model.context.create_pool = false; ctrl.createChange(); expect(scope.model.context.create_listener).toBe(true); expect(scope.model.context.create_monitor).toBe(false); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021500000000000010213 xustar00119 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.help.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.0000664000175100017510000000356015033037474032664 0ustar00mylesmyles

A pool represents a group of members over which the load balancing will be applied.

Algorithm: The load balancer algorithm that distributes traffic to the pool members.

  • LEAST_CONNECTIONS: Allocates requests to the instance with the least number of active connections.
  • ROUND_ROBIN: Rotates requests evenly between multiple instances.
  • SOURCE_IP: Requests from a unique source IP address are consistently directed to the same instance.

Protocol: The protocol for which this pool and its members listen. A valid value is HTTP, HTTPS, PROXY, PROXYV2, TCP, UDP or SCTP.

Session Persistence: The type of session persistence for distributing traffic to the pool members.

  • SOURCE_IP: Session persistence based on source ip.
  • HTTP_COOKIE: Session persistence based on http cookie.
  • APP_COOKIE: Session persistence based on application cookie.

TLS Enabled: Enable TLS for backend re-encryption, communications between the load balancer and the member servers are encrypted.

TLS Cipher String: A string of the allowed ciphers using the OpenSSL syntax. The syntax is a colon separated list of the chiphers, ex. "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256" Note, don't include quotation marks. An empty string sets the default TLS Cipher String configured in Octavia.

././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.html 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.0000664000175100017510000001333315033037474032663 0ustar00mylesmyles

Provide the details for the pool.

{$ ::ctrl.tls_ciphersError $}
././@PaxHeader0000000000000000000000000000021500000000000010213 xustar00119 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.s0000664000175100017510000001074415033037474033001 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function () { 'use strict'; angular .module('horizon.dashboard.project.lbaasv2') .factory('horizon.dashboard.project.lbaasv2.workflow.workflow', lbaasWorkflow); lbaasWorkflow.$inject = [ 'horizon.dashboard.project.lbaasv2.basePath', 'horizon.app.core.workflow.factory', 'horizon.framework.util.i18n.gettext' ]; function lbaasWorkflow(basePath, dashboardWorkflow, gettext) { var workflowSteps = [ { id: 'loadbalancer', title: gettext('Load Balancer Details'), templateUrl: basePath + 'workflow/loadbalancer/loadbalancer.html', helpUrl: basePath + 'workflow/loadbalancer/loadbalancer.help.html', formName: 'loadBalancerDetailsForm' }, { id: 'listener', title: gettext('Listener Details'), templateUrl: basePath + 'workflow/listener/listener.html', helpUrl: basePath + 'workflow/listener/listener.help.html', formName: 'listenerDetailsForm' }, { id: 'l7policy', title: gettext('L7 Policy Details'), templateUrl: basePath + 'workflow/l7policy/l7policy.html', helpUrl: basePath + 'workflow/l7policy/l7policy.help.html', formName: 'l7policyDetailsForm' }, { id: 'l7rule', title: gettext('L7 Rule Details'), templateUrl: basePath + 'workflow/l7rule/l7rule.html', helpUrl: basePath + 'workflow/l7rule/l7rule.help.html', formName: 'l7ruleDetailsForm' }, { id: 'pool', title: gettext('Pool Details'), templateUrl: basePath + 'workflow/pool/pool.html', helpUrl: basePath + 'workflow/pool/pool.help.html', formName: 'poolDetailsForm' }, { id: 'members', title: gettext('Pool Members'), templateUrl: basePath + 'workflow/members/members.html', helpUrl: basePath + 'workflow/members/members.help.html', formName: 'memberDetailsForm' }, { id: 'monitor', title: gettext('Monitor Details'), templateUrl: basePath + 'workflow/monitor/monitor.html', helpUrl: basePath + 'workflow/monitor/monitor.help.html', formName: 'monitorDetailsForm' }, { id: 'certificates', title: gettext('SSL Certificates'), templateUrl: basePath + 'workflow/certificates/certificates.html', helpUrl: basePath + 'workflow/certificates/certificates.help.html', formName: 'certificateDetailsForm' } ]; return initWorkflow; function initWorkflow(title, icon, steps) { var filteredSteps = Array.isArray(steps) ? workflowSteps .filter( function(workflowStep) { return steps.some(function(step) { if (step.id) { return step.id === workflowStep.id; } else { return step === workflowStep.id; } }); } ) : workflowSteps; if (filteredSteps.length === 0) { filteredSteps = workflowSteps; } filteredSteps = filteredSteps.map(function(filteredStep) { filteredStep = angular.copy(filteredStep); if (!Array.isArray(steps)) { return filteredStep; } var step = steps.filter(function(step) { if (step.id) { return step.id === filteredStep.id; } else { return step === filteredStep.id; } })[0]; var deferred; if (step) { deferred = step.deferred; } if (deferred) { var promise = deferred.promise; filteredStep.checkReadiness = function() { return promise; }; } return filteredStep; }); return dashboardWorkflow({ title: title, btnText: { finish: title }, btnIcon: { finish: icon }, steps: filteredSteps }); } } })(); ././@PaxHeader0000000000000000000000000000022200000000000010211 xustar00124 path=octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.spec.js 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.s0000664000175100017510000000716115033037474033000 0ustar00mylesmyles/* * Copyright 2015 IBM Corp. * * 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. */ (function() { 'use strict'; describe('LBaaS v2 Workflow Service', function() { var workflowService, $q; beforeEach(module('horizon.app.core')); beforeEach(module('horizon.framework.util')); beforeEach(module('horizon.framework.conf')); beforeEach(module('horizon.framework.widgets.toast')); beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach(inject(function ($injector) { workflowService = $injector.get( 'horizon.dashboard.project.lbaasv2.workflow.workflow' ); $q = $injector.get('$q'); })); it('should be defined', function () { expect(workflowService).toBeDefined(); }); it('should have a title property', function () { var workflow = workflowService('My Workflow'); expect(workflow.title).toBe('My Workflow'); }); it('should have default steps defined', function () { var workflow = workflowService('My Workflow'); expect(workflow.steps).toBeDefined(); expect(workflow.steps.length).toBe(8); var forms = [ 'loadBalancerDetailsForm', 'listenerDetailsForm', 'l7policyDetailsForm', 'l7ruleDetailsForm', 'poolDetailsForm', 'memberDetailsForm', 'monitorDetailsForm', 'certificateDetailsForm' ]; forms.forEach(function(expectedForm, idx) { expect(workflow.steps[idx].formName).toBe(expectedForm); }); workflow = workflowService('My Workflow', 'foo', []); forms.forEach(function(expectedForm, idx) { expect(workflow.steps[idx].formName).toBe(expectedForm); }); }); it('can filter steps', function () { var workflow = workflowService('My Workflow', 'foo', ['listener', 'pool']); expect(workflow.steps).toBeDefined(); expect(workflow.steps.length).toBe(2); expect(workflow.steps[0].checkReadiness).not.toBeDefined(); var forms = [ 'listenerDetailsForm', 'poolDetailsForm' ]; forms.forEach(function(expectedForm, idx) { expect(workflow.steps[idx].formName).toBe(expectedForm); }); }); it('can wait for all steps to be ready', function () { var steps = ['listener', 'certificates'].map(function(step) { return { id: step, deferred: $q.defer() }; }); var workflow = workflowService('My Workflow', 'foo', steps); expect(workflow.steps[0].checkReadiness).toBeDefined(); expect(workflow.steps[0].checkReadiness()).toBe(steps[0].deferred.promise); expect(workflow.steps[1].checkReadiness).toBeDefined(); expect(workflow.steps[1].checkReadiness()).toBe(steps[1].deferred.promise); }); it('can be extended', function () { var workflow = workflowService('My Workflow'); expect(workflow.append).toBeDefined(); expect(workflow.prepend).toBeDefined(); expect(workflow.after).toBeDefined(); expect(workflow.replace).toBeDefined(); expect(workflow.remove).toBeDefined(); expect(workflow.addController).toBeDefined(); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4731007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/tests/0000775000175100017510000000000015033037476022011 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/tests/__init__.py0000664000175100017510000000000015033037474024106 0ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/tests/settings.py0000664000175100017510000000255315033037474024226 0ustar00mylesmyles# Copyright 2018 Walmart. # # 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. # Default to Horizons test settings to avoid any missing keys from horizon.test.settings import * # noqa from openstack_dashboard.test.settings import * # noqa # Update the dashboards with octavia_dashboard import octavia_dashboard.enabled import openstack_dashboard.enabled from openstack_dashboard.utils import settings # pop these keys to avoid log warnings about deprecation # update_dashboards will populate them anyway HORIZON_CONFIG.pop('dashboards', None) HORIZON_CONFIG.pop('default_dashboard', None) settings.update_dashboards( [ octavia_dashboard.enabled, openstack_dashboard.enabled, ], HORIZON_CONFIG, INSTALLED_APPS ) # Ensure any duplicate apps are removed after the update_dashboards call INSTALLED_APPS = list(set(INSTALLED_APPS)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4731007 octavia_dashboard-15.1.0.dev2/octavia_dashboard/tests/unit/0000775000175100017510000000000015033037476022770 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/tests/unit/__init__.py0000664000175100017510000000000015033037474025065 0ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/tests/unit/registration.py0000664000175100017510000000174415033037474026060 0ustar00mylesmyles# Copyright 2018 Walmart. # # 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 horizon from octavia_dashboard.dashboards.project.load_balancer import panel as o_panel from openstack_dashboard.test import helpers as test class RegistrationTests(test.TestCase): def test_registered(self): dashboard = horizon.get_dashboard('project') panel = dashboard.get_panel('load_balancer') self.assertEqual(panel.__class__, o_panel.NGLoadBalancers) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/tests/urls.py0000664000175100017510000000140515033037474023346 0ustar00mylesmyles# Copyright 2018 Walmart. # # 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 django.conf.urls import include from django.urls import re_path import openstack_dashboard.urls urlpatterns = [ re_path(r'', include(openstack_dashboard.urls)) ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard/version.py0000664000175100017510000000171015033037474022703 0ustar00mylesmyles# Copyright 2011-2014 OpenStack Foundation # # 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 OCTAVIA_VENDOR = "OpenStack Foundation" OCTAVIA_PRODUCT = "OpenStack Octavia Dashboard" version_info = pbr.version.VersionInfo('octavia-dashboard') def vendor_string(): return OCTAVIA_VENDOR def product_string(): return OCTAVIA_PRODUCT def version_string_with_package(): return version_info.version_string() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4651008 octavia_dashboard-15.1.0.dev2/octavia_dashboard.egg-info/0000775000175100017510000000000015033037476022341 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924541.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard.egg-info/PKG-INFO0000644000175100017510000000715315033037475023441 0ustar00mylesmylesMetadata-Version: 2.2 Name: octavia-dashboard Version: 15.1.0.dev2 Summary: Horizon panels for Octavia Home-page: https://docs.openstack.org/octavia-dashboard/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org 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 :: Implementation :: CPython Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Requires-Python: >=3.9 License-File: LICENSE Requires-Dist: horizon>=17.1.0 Requires-Dist: Babel>=2.3.4 Requires-Dist: openstacksdk>=0.53.0 Requires-Dist: pbr>=2.0.0 Requires-Dist: python-keystoneclient>=3.22.0 Dynamic: author Dynamic: author-email Dynamic: classifier Dynamic: description Dynamic: home-page Dynamic: requires-dist Dynamic: requires-python Dynamic: summary ================= Octavia Dashboard ================= Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/octavia-dashboard.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on octavia-dashboard ================= Horizon panels for Octavia * Free software: Apache license * Documentation: https://docs.openstack.org/octavia-dashboard/latest/ * Source: https://opendev.org/openstack/octavia-dashboard * Release notes: https://docs.openstack.org/releasenotes/octavia-dashboard/ * Bugs: https://storyboard.openstack.org/#!/project/909 Features -------- * Please see octavia repository Howto ----- 1. Package the octavia_dashboard by running:: python setup.py sdist This will create a python egg in the dist folder, which can be used to install on the horizon machine or within horizon's python virtual environment. 2. Copy ``_1482_project_load_balancer_panel.py`` in ``octavia_dashboard/enabled`` directory to ``openstack_dashboard/local/enabled``:: $ cp -a \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/enabled/_1482_*.py \ ${HORIZON_DIR}/openstack_dashboard/local/enabled/ 3. (Optional) Generate the policy file and copy into horizon's policy files folder, and copy ``_1499_load_balancer_settings.py`` in ``octavia_dashboard/local_settings.d`` directory to ``openstack_dashboard/local/local_settings.d``:: $ oslopolicy-policy-generator \ --config-file \ ${OCTAVIA_DIR}/etc/policy/octavia-policy-generator.conf \ --output-file \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml $ cp -a \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/conf/octavia_policy.yaml \ ${HORIZON_DIR}/openstack_dashboard/conf/ $ cp -a \ ${OCTAVIA_DASHBOARD_DIR}/octavia_dashboard/local_settings.d/_1499_*.py \ ${HORIZON_DIR}/openstack_dashboard/local/local_settings.d/ 4. Django has a compressor feature that performs many enhancements for the delivery of static files. If the compressor feature is enabled in your environment (``COMPRESS_OFFLINE = True``), run the following commands:: $ ./manage.py collectstatic $ ./manage.py compress 5. Finally restart your web server to enable octavia-dashboard in your Horizon:: $ sudo service apache2 restart ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924541.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard.egg-info/SOURCES.txt0000664000175100017510000005420715033037475024234 0ustar00mylesmyles.coveragerc .eslintrc .mailmap .stestr.conf AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE README.rst babel-django.cfg babel-djangojs.cfg bindep.txt manage.py package-lock.json package.json requirements.txt setup.cfg setup.py test-requirements.txt tox.ini devstack/README.rst devstack/plugin.sh devstack/settings doc/requirements.txt doc/source/conf.py doc/source/contributing.rst doc/source/index.rst doc/source/installation.rst doc/source/readme.rst doc/source/reference.rst octavia_dashboard/__init__.py octavia_dashboard/karma.conf.js octavia_dashboard/post_install.sh octavia_dashboard/sdk_connection.py octavia_dashboard/version.py octavia_dashboard.egg-info/PKG-INFO octavia_dashboard.egg-info/SOURCES.txt octavia_dashboard.egg-info/dependency_links.txt octavia_dashboard.egg-info/not-zip-safe octavia_dashboard.egg-info/pbr.json octavia_dashboard.egg-info/requires.txt octavia_dashboard.egg-info/top_level.txt octavia_dashboard/api/__init__.py octavia_dashboard/api/rest/__init__.py octavia_dashboard/api/rest/barbican.py octavia_dashboard/api/rest/lbaasv2.py octavia_dashboard/conf/.gitkeep octavia_dashboard/dashboards/__init__.py octavia_dashboard/dashboards/project/__init__.py octavia_dashboard/dashboards/project/load_balancer/__init__.py octavia_dashboard/dashboards/project/load_balancer/panel.py octavia_dashboard/dashboards/project/load_balancer/urls.py octavia_dashboard/dashboards/project/load_balancer/views.py octavia_dashboard/dashboards/project/load_balancer/templates/load_balancer/index.html octavia_dashboard/enabled/_1482_project_load_balancer_panel.py octavia_dashboard/enabled/__init__.py octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py octavia_dashboard/locale/de/LC_MESSAGES/django.po octavia_dashboard/locale/de/LC_MESSAGES/djangojs.po octavia_dashboard/locale/en_AU/LC_MESSAGES/django.po octavia_dashboard/locale/en_GB/LC_MESSAGES/django.po octavia_dashboard/locale/en_GB/LC_MESSAGES/djangojs.po octavia_dashboard/locale/es/LC_MESSAGES/django.po octavia_dashboard/locale/fr/LC_MESSAGES/django.po octavia_dashboard/locale/id/LC_MESSAGES/django.po octavia_dashboard/locale/id/LC_MESSAGES/djangojs.po octavia_dashboard/locale/ja/LC_MESSAGES/django.po octavia_dashboard/locale/ja/LC_MESSAGES/djangojs.po octavia_dashboard/locale/ko_KR/LC_MESSAGES/django.po octavia_dashboard/locale/ko_KR/LC_MESSAGES/djangojs.po octavia_dashboard/locale/pt_BR/LC_MESSAGES/django.po octavia_dashboard/locale/ru/LC_MESSAGES/django.po octavia_dashboard/locale/ru/LC_MESSAGES/djangojs.po octavia_dashboard/locale/zh_Hans/LC_MESSAGES/django.po octavia_dashboard/locale/zh_Hans/LC_MESSAGES/djangojs.po octavia_dashboard/locale/zh_Hant/LC_MESSAGES/django.po octavia_dashboard/locale/zh_Hant/LC_MESSAGES/djangojs.po octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js octavia_dashboard/static/app/core/openstack-service-api/octavia-barbican.service.js octavia_dashboard/static/app/core/openstack-service-api/octavia-barbican.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.js octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.scss octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/healthmonitors.module.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/healthmonitors.module.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/create.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/create.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/delete/delete.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/delete/delete.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/detail.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/detail.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/detail.html octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/drawer.html octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.html octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/drawer.html octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.html octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/drawer.html octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners.module.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners.module.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/create.service.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/create.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/delete/delete.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/delete/delete.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/edit.service.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/edit.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.html octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/drawer.html octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.module.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.module.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel.html octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.html octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.service.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/create.service.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/create.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/delete/delete.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/delete/delete.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/disassociate-ip/modal.service.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/disassociate-ip/modal.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/edit.service.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/edit.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/detail.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/detail.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/detail.html octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/drawer.html octavia_dashboard/static/dashboard/project/lbaasv2/members/members.module.js octavia_dashboard/static/dashboard/project/lbaasv2/members/members.module.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/delete/delete.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/delete/delete.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.html octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.service.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/update-member-list.service.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/update-member-list.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/members/details/detail.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/members/details/detail.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/members/details/detail.html octavia_dashboard/static/dashboard/project/lbaasv2/members/details/drawer.html octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delete/delete.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delete/delete.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/edit.action.service.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/edit.action.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/wizard.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/wizard.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detail.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detail.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detail.html octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/drawer.html octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/validate-unique.js octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/validate-unique.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/filter-select.component.js octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/filter-select.component.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/filter-select.html octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table-status.directive.js octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table-status.directive.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table-status.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.service.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.help.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.help.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.help.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.help.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.help.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.help.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.help.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.controller.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.controller.spec.js octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.help.html octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.html octavia_dashboard/tests/__init__.py octavia_dashboard/tests/settings.py octavia_dashboard/tests/urls.py octavia_dashboard/tests/unit/__init__.py octavia_dashboard/tests/unit/registration.py releasenotes/notes/Add-ProxyV2-b5537c092737fe41.yaml releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml releasenotes/notes/add-RBAC-43ee180e712294ed.yaml releasenotes/notes/add-allowed-cidrs-ad205b1524da3d2c.yaml releasenotes/notes/add-az-support-efdd4e7c5dccef21.yaml releasenotes/notes/add-ciphers-options-for-listeners-and-pools-8440eaf5a551c44c.yaml releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml releasenotes/notes/add-insert-headers-a6fd80c837a89536.yaml releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml releasenotes/notes/add-member-backup-32e2ec2553c1ba24.yaml releasenotes/notes/add-sctp-support-a1ea956b7630f47d.yaml releasenotes/notes/add-timeout-options-8988fc477fa46d31.yaml releasenotes/notes/add-tls_enabled-support-for-pools-449e39f851535839.yaml releasenotes/notes/add-udp-support-acb1a22fb605d3a8.yaml releasenotes/notes/add-x-forwarded-proto-e30b52a3f853ed62.yaml releasenotes/notes/allows-creation-of-single-resources-9ec5fe87acc7c93c.yaml releasenotes/notes/auto-refresh-detail-pages-26166d5d9c26edee.yaml releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml releasenotes/notes/cascade-delete-e4c9d80a31076540.yaml releasenotes/notes/drop-py-2-7-f3372b5c26171513.yaml releasenotes/notes/edit-default-pool-on-listener-206d8dfeea135360.yaml releasenotes/notes/filter-select-65160dcbe699a96d.yaml releasenotes/notes/fix-auth-issue-5226777261765699.yaml releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml releasenotes/notes/fix-certificate-list-listener-edit-1d9775d23692c34b.yaml releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml releasenotes/notes/fix-flavor-no-flavor-profile-c3e82325f16d5ab8.yaml releasenotes/notes/fix-incorrect-region-endpoint-1afc5ebdc6fc4110.yaml releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml releasenotes/notes/flavor-support-0195a486faa16b7f.yaml releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml releasenotes/notes/list-pools-on-lb-details-page-eb0400bdb2b3650f.yaml releasenotes/notes/move-to-python-3.8-86095fce6076fb37.yaml releasenotes/notes/pool-selection-hint-7f282ba1fa014d8c.yaml releasenotes/notes/remove-barbicanclient-6b48fcc36afafb62.yaml releasenotes/source/2023.1.rst releasenotes/source/2023.2.rst releasenotes/source/2024.1.rst releasenotes/source/2024.2.rst releasenotes/source/2025.1.rst releasenotes/source/conf.py releasenotes/source/index.rst releasenotes/source/queens.rst releasenotes/source/rocky.rst releasenotes/source/stein.rst releasenotes/source/train.rst releasenotes/source/unreleased.rst releasenotes/source/ussuri.rst releasenotes/source/victoria.rst releasenotes/source/wallaby.rst releasenotes/source/xena.rst releasenotes/source/yoga.rst releasenotes/source/zed.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder releasenotes/source/locale/de/LC_MESSAGES/releasenotes.po releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po releasenotes/source/locale/id/LC_MESSAGES/releasenotes.po releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po releasenotes/source/locale/zh_CN/LC_MESSAGES/releasenotes.po releasenotes/source/locale/zh_TW/LC_MESSAGES/releasenotes.po zuul.d/projects.yaml././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924541.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard.egg-info/dependency_links.txt0000664000175100017510000000000115033037475026406 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924541.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard.egg-info/not-zip-safe0000664000175100017510000000000115033037475024566 0ustar00mylesmyles ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924541.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard.egg-info/pbr.json0000664000175100017510000000005715033037475024020 0ustar00mylesmyles{"git_version": "890ed46", "is_release": false}././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924541.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard.egg-info/requires.txt0000664000175100017510000000013315033037475024735 0ustar00mylesmyleshorizon>=17.1.0 Babel>=2.3.4 openstacksdk>=0.53.0 pbr>=2.0.0 python-keystoneclient>=3.22.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924541.0 octavia_dashboard-15.1.0.dev2/octavia_dashboard.egg-info/top_level.txt0000664000175100017510000000002215033037475025064 0ustar00mylesmylesoctavia_dashboard ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/package-lock.json0000664000175100017510000047160015033037474020434 0ustar00mylesmyles{ "name": "octavia-dashboard", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", "dev": true }, "accepts": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.1.4.tgz", "integrity": "sha1-1xyW99QdD+2iw4zRToonwEFY30o=", "dev": true, "requires": { "mime-types": "2.0.14", "negotiator": "0.4.9" }, "dependencies": { "mime-db": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz", "integrity": "sha1-PQxjGA9FjrENMlqqN9fFiuMS6dc=", "dev": true }, "mime-types": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz", "integrity": "sha1-MQ4VnbI+B3+Lsit0jav6SVcUCqY=", "dev": true, "requires": { "mime-db": "1.12.0" } } } }, "after": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/after/-/after-0.8.1.tgz", "integrity": "sha1-q11PuIP1loFtNRX495HAr0ht1ic=", "dev": true }, "align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { "kind-of": "3.2.2", "longest": "1.0.1", "repeat-string": "1.6.1" } }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, "ansi-escapes": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", "dev": true }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", "dev": true, "requires": { "micromatch": "2.3.11", "normalize-path": "2.1.1" } }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "1.0.3" } }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { "arr-flatten": "1.1.0" } }, "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, "array-slice": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", "dev": true }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { "array-uniq": "1.0.3" } }, "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", "dev": true }, "array-unique": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", "dev": true }, "arraybuffer.slice": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=", "dev": true }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "asn1": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", "dev": true }, "assert-plus": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", "dev": true }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, "async-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "dev": true }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, "aws-sign2": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", "dev": true }, "aws4": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", "dev": true }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "base64-arraybuffer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz", "integrity": "sha1-R030qfLaJOBd8xWMOx2zw81GoVQ=", "dev": true }, "base64id": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz", "integrity": "sha1-As4P3u4M709ACA4ec+g08LG/zj8=", "dev": true }, "bcrypt-pbkdf": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "dev": true, "optional": true, "requires": { "tweetnacl": "0.14.5" } }, "benchmark": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-1.0.0.tgz", "integrity": "sha1-Lx4vpMNZ8REiqhgwgiGOlX45DHM=", "dev": true }, "better-assert": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", "dev": true, "requires": { "callsite": "1.0.0" } }, "binary-extensions": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", "dev": true }, "blob": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", "dev": true }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", "dev": true }, "body-parser": { "version": "1.18.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", "dev": true, "requires": { "bytes": "3.0.0", "content-type": "1.0.4", "debug": "2.6.9", "depd": "1.1.2", "http-errors": "1.6.2", "iconv-lite": "0.4.19", "on-finished": "2.3.0", "qs": "6.5.1", "raw-body": "2.3.2", "type-is": "1.6.16" } }, "boom": { "version": "2.10.1", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, "requires": { "hoek": "2.16.3" } }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, "braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { "expand-range": "1.8.2", "preserve": "0.2.0", "repeat-element": "1.1.2" } }, "buffer-from": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", "dev": true }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", "dev": true }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", "dev": true }, "camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", "dev": true, "optional": true }, "camelcase-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { "camelcase": "2.1.1", "map-obj": "1.0.1" }, "dependencies": { "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", "dev": true } } }, "caseless": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", "dev": true }, "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, "optional": true, "requires": { "align-text": "0.1.4", "lazy-cache": "1.0.4" } }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { "ansi-styles": "2.2.1", "escape-string-regexp": "1.0.5", "has-ansi": "2.0.0", "strip-ansi": "3.0.1", "supports-color": "2.0.0" } }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", "dev": true, "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", "fsevents": "1.1.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", "is-glob": "2.0.1", "path-is-absolute": "1.0.1", "readdirp": "2.1.0" } }, "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, "cli-cursor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", "dev": true, "requires": { "restore-cursor": "1.0.1" } }, "cli-width": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", "integrity": "sha1-pNKT72frt7iNSk1CwMzwDE0eNm0=", "dev": true }, "cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, "optional": true, "requires": { "center-align": "0.1.3", "right-align": "0.1.3", "wordwrap": "0.0.2" }, "dependencies": { "wordwrap": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", "dev": true, "optional": true } } }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "colors": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.1.tgz", "integrity": "sha512-s8+wktIuDSLffCywiwSxQOMqtPxML11a/dtHE17tMn4B1MSWw/C22EKf7M2KGUBcDaVFEGT+S8N02geDXeuNKg==", "dev": true }, "combine-lists": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", "dev": true, "requires": { "lodash": "4.17.5" }, "dependencies": { "lodash": { "version": "4.17.5", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", "dev": true } } }, "combined-stream": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "dev": true, "requires": { "delayed-stream": "1.0.0" } }, "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", "dev": true }, "component-emitter": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=", "dev": true }, "component-inherit": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { "buffer-from": "1.0.0", "inherits": "2.0.3", "readable-stream": "2.3.5", "typedarray": "0.0.6" } }, "connect": { "version": "3.6.6", "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", "dev": true, "requires": { "debug": "2.6.9", "finalhandler": "1.1.0", "parseurl": "1.3.2", "utils-merge": "1.0.1" } }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "core-js": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=", "dev": true }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, "cryptiles": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", "dev": true, "requires": { "boom": "2.10.1" } }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "dev": true, "requires": { "array-find-index": "1.0.2" } }, "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", "dev": true }, "d": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true, "requires": { "es5-ext": "0.10.41" } }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "dev": true, "requires": { "assert-plus": "1.0.0" }, "dependencies": { "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true } } }, "dateformat": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", "dev": true, "requires": { "get-stdin": "4.0.1", "meow": "3.7.0" } }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, "del": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", "dev": true, "requires": { "globby": "5.0.0", "is-path-cwd": "1.0.0", "is-path-in-cwd": "1.0.0", "object-assign": "4.1.1", "pify": "2.3.0", "pinkie-promise": "2.0.1", "rimraf": "2.6.2" } }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "dev": true }, "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", "dev": true }, "doctrine": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz", "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=", "dev": true, "requires": { "esutils": "1.1.6", "isarray": "0.0.1" }, "dependencies": { "esutils": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=", "dev": true }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true } } }, "dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", "dev": true, "requires": { "custom-event": "1.0.1", "ent": "2.2.0", "extend": "3.0.1", "void-elements": "2.0.1" } }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "dev": true, "optional": true, "requires": { "jsbn": "0.1.1" } }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, "engine.io": { "version": "1.6.10", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.6.10.tgz", "integrity": "sha1-+H2E4b0h0aLsf43u8MYgVKzfsno=", "dev": true, "requires": { "accepts": "1.1.4", "base64id": "0.1.0", "debug": "2.2.0", "engine.io-parser": "1.2.4", "ws": "1.0.1" }, "dependencies": { "debug": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", "dev": true, "requires": { "ms": "0.7.1" } }, "ms": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", "dev": true } } }, "engine.io-client": { "version": "1.6.9", "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.6.9.tgz", "integrity": "sha1-HWrUgEilCDyVCWlDsp0279shJAE=", "dev": true, "requires": { "component-emitter": "1.1.2", "component-inherit": "0.0.3", "debug": "2.2.0", "engine.io-parser": "1.2.4", "has-cors": "1.1.0", "indexof": "0.0.1", "parsejson": "0.0.1", "parseqs": "0.0.2", "parseuri": "0.0.4", "ws": "1.0.1", "xmlhttprequest-ssl": "1.5.1", "yeast": "0.1.2" }, "dependencies": { "debug": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", "dev": true, "requires": { "ms": "0.7.1" } }, "ms": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", "dev": true } } }, "engine.io-parser": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.2.4.tgz", "integrity": "sha1-4Il7C/FOeS1M0qWVBVORnFaUjEI=", "dev": true, "requires": { "after": "0.8.1", "arraybuffer.slice": "0.0.6", "base64-arraybuffer": "0.1.2", "blob": "0.0.4", "has-binary": "0.1.6", "utf8": "2.1.0" }, "dependencies": { "has-binary": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz", "integrity": "sha1-JTJvOc+k9hath4eJTjryz7x7bhA=", "dev": true, "requires": { "isarray": "0.0.1" } }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true } } }, "ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", "dev": true }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { "is-arrayish": "0.2.1" } }, "es5-ext": { "version": "0.10.41", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.41.tgz", "integrity": "sha512-MYK02wXfwTMie5TEJWPolgOsXEmz7wKCQaGzgmRjZOoV6VLG8I5dSv2bn6AOClXhK64gnSQTQ9W9MKvx87J4gw==", "dev": true, "requires": { "es6-iterator": "2.0.3", "es6-symbol": "3.1.1", "next-tick": "1.0.0" } }, "es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", "dev": true, "requires": { "d": "1.0.0", "es5-ext": "0.10.41", "es6-symbol": "3.1.1" } }, "es6-map": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", "dev": true, "requires": { "d": "1.0.0", "es5-ext": "0.10.41", "es6-iterator": "2.0.3", "es6-set": "0.1.5", "es6-symbol": "3.1.1", "event-emitter": "0.3.5" } }, "es6-promise": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz", "integrity": "sha1-eILzCt3lskDM+n99eMVIMwlRrkI=", "dev": true }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", "dev": true, "requires": { "d": "1.0.0", "es5-ext": "0.10.41", "es6-iterator": "2.0.3", "es6-symbol": "3.1.1", "event-emitter": "0.3.5" } }, "es6-symbol": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", "dev": true, "requires": { "d": "1.0.0", "es5-ext": "0.10.41" } }, "es6-weak-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { "d": "1.0.0", "es5-ext": "0.10.41", "es6-iterator": "2.0.3", "es6-symbol": "3.1.1" } }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "escodegen": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", "dev": true, "requires": { "esprima": "2.7.3", "estraverse": "1.9.3", "esutils": "2.0.2", "optionator": "0.8.2", "source-map": "0.2.0" }, "dependencies": { "esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", "dev": true }, "estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", "dev": true }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { "prelude-ls": "1.1.2", "type-check": "0.3.2" } }, "optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { "deep-is": "0.1.3", "fast-levenshtein": "2.0.6", "levn": "0.3.0", "prelude-ls": "1.1.2", "type-check": "0.3.2", "wordwrap": "1.0.0" } }, "source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, "optional": true, "requires": { "amdefine": "1.0.1" } }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true } } }, "escope": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", "dev": true, "requires": { "es6-map": "0.1.5", "es6-weak-map": "2.0.2", "esrecurse": "4.2.1", "estraverse": "4.2.0" } }, "eslint": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/eslint/-/eslint-1.10.3.tgz", "integrity": "sha1-+xmpGxPBWAgrvKKUsX2Xm8g1Ogo=", "dev": true, "requires": { "chalk": "1.1.3", "concat-stream": "1.6.2", "debug": "2.6.9", "doctrine": "0.7.2", "escape-string-regexp": "1.0.5", "escope": "3.6.0", "espree": "2.2.5", "estraverse": "4.2.0", "estraverse-fb": "1.3.2", "esutils": "2.0.2", "file-entry-cache": "1.3.1", "glob": "5.0.15", "globals": "8.18.0", "handlebars": "4.0.11", "inquirer": "0.11.4", "is-my-json-valid": "2.17.2", "is-resolvable": "1.1.0", "js-yaml": "3.4.5", "json-stable-stringify": "1.0.1", "lodash.clonedeep": "3.0.2", "lodash.merge": "3.3.2", "lodash.omit": "3.1.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", "object-assign": "4.1.1", "optionator": "0.6.0", "path-is-absolute": "1.0.1", "path-is-inside": "1.0.2", "shelljs": "0.5.3", "strip-json-comments": "1.0.4", "text-table": "0.2.0", "user-home": "2.0.0", "xml-escape": "1.0.0" } }, "eslint-config-openstack": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/eslint-config-openstack/-/eslint-config-openstack-1.2.4.tgz", "integrity": "sha1-cEHmUbPDsdCVjmv6IGBWahRMYgk=", "dev": true, "requires": { "js-yaml": "3.3.1" }, "dependencies": { "esprima": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.2.0.tgz", "integrity": "sha1-QpLB1o5Bc9gV+iKQ3Hr8ltgfzYM=", "dev": true }, "js-yaml": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.3.1.tgz", "integrity": "sha1-yhrNNCPsJ10SFAp7q1HbAVugs8A=", "dev": true, "requires": { "argparse": "1.0.10", "esprima": "2.2.0" } } } }, "eslint-plugin-angular": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-angular/-/eslint-plugin-angular-1.0.1.tgz", "integrity": "sha1-vSus9cj2iJbLe4Rhe0E+cRS8f+0=", "dev": true, "requires": { "lodash": "4.17.5" }, "dependencies": { "lodash": { "version": "4.17.5", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", "dev": true } } }, "espree": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", "integrity": "sha1-32kbkxCIlAKuspzAZnCMVmkLhUs=", "dev": true }, "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { "estraverse": "4.2.0" } }, "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "dev": true }, "estraverse-fb": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.2.tgz", "integrity": "sha1-0yOky15awzHOoDNBOpJT4WQ+B8Q=", "dev": true }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", "dev": true, "requires": { "d": "1.0.0", "es5-ext": "0.10.41" } }, "eventemitter3": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", "dev": true }, "exit-hook": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", "dev": true }, "expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", "dev": true, "requires": { "array-slice": "0.2.3", "array-unique": "0.2.1", "braces": "0.1.5" }, "dependencies": { "braces": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", "dev": true, "requires": { "expand-range": "0.1.1" } }, "expand-range": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", "dev": true, "requires": { "is-number": "0.1.1", "repeat-string": "0.2.2" } }, "is-number": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", "dev": true }, "repeat-string": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", "dev": true } } }, "expand-brackets": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { "is-posix-bracket": "0.1.1" } }, "expand-range": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { "fill-range": "2.2.3" } }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", "dev": true }, "extglob": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { "is-extglob": "1.0.0" } }, "extract-zip": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", "integrity": "sha1-ksz22B73Cp+kwXRxFMzvbYaIpsQ=", "dev": true, "requires": { "concat-stream": "1.5.0", "debug": "0.7.4", "mkdirp": "0.5.0", "yauzl": "2.4.1" }, "dependencies": { "concat-stream": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz", "integrity": "sha1-U/fUPFHF5D+ByP3QMyHGMb5o1hE=", "dev": true, "requires": { "inherits": "2.0.3", "readable-stream": "2.0.6", "typedarray": "0.0.6" } }, "debug": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", "dev": true }, "mkdirp": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", "dev": true, "requires": { "minimist": "0.0.8" } }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", "dev": true }, "readable-stream": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "dev": true, "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", "isarray": "1.0.0", "process-nextick-args": "1.0.7", "string_decoder": "0.10.31", "util-deprecate": "1.0.2" } }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } } }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, "fast-levenshtein": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz", "integrity": "sha1-AXjc3uAjuSkFGTrwlZ6KdjnP3Lk=", "dev": true }, "fd-slicer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", "dev": true, "requires": { "pend": "1.2.0" } }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true, "requires": { "escape-string-regexp": "1.0.5", "object-assign": "4.1.1" } }, "file-entry-cache": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz", "integrity": "sha1-RMYepgeuS+nBQC9B9EJwy/4zT/g=", "dev": true, "requires": { "flat-cache": "1.3.0", "object-assign": "4.1.1" } }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", "dev": true }, "fileset": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", "integrity": "sha1-WI74lzxmI7KnbfRlEFaWuWqsgGc=", "dev": true, "requires": { "glob": "5.0.15", "minimatch": "2.0.10" }, "dependencies": { "minimatch": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", "dev": true, "requires": { "brace-expansion": "1.1.11" } } } }, "fill-range": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", "dev": true, "requires": { "is-number": "2.1.0", "isobject": "2.1.0", "randomatic": "1.1.7", "repeat-element": "1.1.2", "repeat-string": "1.6.1" } }, "finalhandler": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", "dev": true, "requires": { "debug": "2.6.9", "encodeurl": "1.0.2", "escape-html": "1.0.3", "on-finished": "2.3.0", "parseurl": "1.3.2", "statuses": "1.3.1", "unpipe": "1.0.0" }, "dependencies": { "statuses": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", "dev": true } } }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { "path-exists": "2.1.0", "pinkie-promise": "2.0.1" } }, "flat-cache": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", "dev": true, "requires": { "circular-json": "0.3.3", "del": "2.2.2", "graceful-fs": "4.1.11", "write": "0.2.1" } }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, "for-own": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "dev": true, "requires": { "for-in": "1.0.2" } }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "dev": true }, "form-data": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", "dev": true, "requires": { "asynckit": "0.4.0", "combined-stream": "1.0.6", "mime-types": "2.1.18" } }, "fs-access": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", "dev": true, "requires": { "null-check": "1.0.0" } }, "fs-extra": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", "dev": true, "requires": { "graceful-fs": "4.1.11", "jsonfile": "2.4.0", "klaw": "1.3.1" } }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "fsevents": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", "dev": true, "optional": true, "requires": { "nan": "2.10.0", "node-pre-gyp": "0.6.39" }, "dependencies": { "abbrev": { "version": "1.1.0", "bundled": true, "dev": true, "optional": true }, "ajv": { "version": "4.11.8", "bundled": true, "dev": true, "optional": true, "requires": { "co": "4.6.0", "json-stable-stringify": "1.0.1" } }, "ansi-regex": { "version": "2.1.1", "bundled": true, "dev": true }, "aproba": { "version": "1.1.1", "bundled": true, "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", "bundled": true, "dev": true, "optional": true, "requires": { "delegates": "1.0.0", "readable-stream": "2.2.9" } }, "asn1": { "version": "0.2.3", "bundled": true, "dev": true, "optional": true }, "assert-plus": { "version": "0.2.0", "bundled": true, "dev": true, "optional": true }, "asynckit": { "version": "0.4.0", "bundled": true, "dev": true, "optional": true }, "aws-sign2": { "version": "0.6.0", "bundled": true, "dev": true, "optional": true }, "aws4": { "version": "1.6.0", "bundled": true, "dev": true, "optional": true }, "balanced-match": { "version": "0.4.2", "bundled": true, "dev": true }, "bcrypt-pbkdf": { "version": "1.0.1", "bundled": true, "dev": true, "optional": true, "requires": { "tweetnacl": "0.14.5" } }, "block-stream": { "version": "0.0.9", "bundled": true, "dev": true, "requires": { "inherits": "2.0.3" } }, "boom": { "version": "2.10.1", "bundled": true, "dev": true, "requires": { "hoek": "2.16.3" } }, "brace-expansion": { "version": "1.1.7", "bundled": true, "dev": true, "requires": { "balanced-match": "0.4.2", "concat-map": "0.0.1" } }, "buffer-shims": { "version": "1.0.0", "bundled": true, "dev": true }, "caseless": { "version": "0.12.0", "bundled": true, "dev": true, "optional": true }, "co": { "version": "4.6.0", "bundled": true, "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", "bundled": true, "dev": true }, "combined-stream": { "version": "1.0.5", "bundled": true, "dev": true, "requires": { "delayed-stream": "1.0.0" } }, "concat-map": { "version": "0.0.1", "bundled": true, "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, "dev": true }, "core-util-is": { "version": "1.0.2", "bundled": true, "dev": true }, "cryptiles": { "version": "2.0.5", "bundled": true, "dev": true, "requires": { "boom": "2.10.1" } }, "dashdash": { "version": "1.14.1", "bundled": true, "dev": true, "optional": true, "requires": { "assert-plus": "1.0.0" }, "dependencies": { "assert-plus": { "version": "1.0.0", "bundled": true, "dev": true, "optional": true } } }, "debug": { "version": "2.6.8", "bundled": true, "dev": true, "optional": true, "requires": { "ms": "2.0.0" } }, "deep-extend": { "version": "0.4.2", "bundled": true, "dev": true, "optional": true }, "delayed-stream": { "version": "1.0.0", "bundled": true, "dev": true }, "delegates": { "version": "1.0.0", "bundled": true, "dev": true, "optional": true }, "detect-libc": { "version": "1.0.2", "bundled": true, "dev": true, "optional": true }, "ecc-jsbn": { "version": "0.1.1", "bundled": true, "dev": true, "optional": true, "requires": { "jsbn": "0.1.1" } }, "extend": { "version": "3.0.1", "bundled": true, "dev": true, "optional": true }, "extsprintf": { "version": "1.0.2", "bundled": true, "dev": true }, "forever-agent": { "version": "0.6.1", "bundled": true, "dev": true, "optional": true }, "form-data": { "version": "2.1.4", "bundled": true, "dev": true, "optional": true, "requires": { "asynckit": "0.4.0", "combined-stream": "1.0.5", "mime-types": "2.1.15" } }, "fs.realpath": { "version": "1.0.0", "bundled": true, "dev": true }, "fstream": { "version": "1.0.11", "bundled": true, "dev": true, "requires": { "graceful-fs": "4.1.11", "inherits": "2.0.3", "mkdirp": "0.5.1", "rimraf": "2.6.1" } }, "fstream-ignore": { "version": "1.0.5", "bundled": true, "dev": true, "optional": true, "requires": { "fstream": "1.0.11", "inherits": "2.0.3", "minimatch": "3.0.4" } }, "gauge": { "version": "2.7.4", "bundled": true, "dev": true, "optional": true, "requires": { "aproba": "1.1.1", "console-control-strings": "1.1.0", "has-unicode": "2.0.1", "object-assign": "4.1.1", "signal-exit": "3.0.2", "string-width": "1.0.2", "strip-ansi": "3.0.1", "wide-align": "1.1.2" } }, "getpass": { "version": "0.1.7", "bundled": true, "dev": true, "optional": true, "requires": { "assert-plus": "1.0.0" }, "dependencies": { "assert-plus": { "version": "1.0.0", "bundled": true, "dev": true, "optional": true } } }, "glob": { "version": "7.1.2", "bundled": true, "dev": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.3", "minimatch": "3.0.4", "once": "1.4.0", "path-is-absolute": "1.0.1" } }, "graceful-fs": { "version": "4.1.11", "bundled": true, "dev": true }, "har-schema": { "version": "1.0.5", "bundled": true, "dev": true, "optional": true }, "har-validator": { "version": "4.2.1", "bundled": true, "dev": true, "optional": true, "requires": { "ajv": "4.11.8", "har-schema": "1.0.5" } }, "has-unicode": { "version": "2.0.1", "bundled": true, "dev": true, "optional": true }, "hawk": { "version": "3.1.3", "bundled": true, "dev": true, "requires": { "boom": "2.10.1", "cryptiles": "2.0.5", "hoek": "2.16.3", "sntp": "1.0.9" } }, "hoek": { "version": "2.16.3", "bundled": true, "dev": true }, "http-signature": { "version": "1.1.1", "bundled": true, "dev": true, "optional": true, "requires": { "assert-plus": "0.2.0", "jsprim": "1.4.0", "sshpk": "1.13.0" } }, "inflight": { "version": "1.0.6", "bundled": true, "dev": true, "requires": { "once": "1.4.0", "wrappy": "1.0.2" } }, "inherits": { "version": "2.0.3", "bundled": true, "dev": true }, "ini": { "version": "1.3.4", "bundled": true, "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, "dev": true, "requires": { "number-is-nan": "1.0.1" } }, "is-typedarray": { "version": "1.0.0", "bundled": true, "dev": true, "optional": true }, "isarray": { "version": "1.0.0", "bundled": true, "dev": true }, "isstream": { "version": "0.1.2", "bundled": true, "dev": true, "optional": true }, "jodid25519": { "version": "1.0.2", "bundled": true, "dev": true, "optional": true, "requires": { "jsbn": "0.1.1" } }, "jsbn": { "version": "0.1.1", "bundled": true, "dev": true, "optional": true }, "json-schema": { "version": "0.2.3", "bundled": true, "dev": true, "optional": true }, "json-stable-stringify": { "version": "1.0.1", "bundled": true, "dev": true, "optional": true, "requires": { "jsonify": "0.0.0" } }, "json-stringify-safe": { "version": "5.0.1", "bundled": true, "dev": true, "optional": true }, "jsonify": { "version": "0.0.0", "bundled": true, "dev": true, "optional": true }, "jsprim": { "version": "1.4.0", "bundled": true, "dev": true, "optional": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.0.2", "json-schema": "0.2.3", "verror": "1.3.6" }, "dependencies": { "assert-plus": { "version": "1.0.0", "bundled": true, "dev": true, "optional": true } } }, "mime-db": { "version": "1.27.0", "bundled": true, "dev": true }, "mime-types": { "version": "2.1.15", "bundled": true, "dev": true, "requires": { "mime-db": "1.27.0" } }, "minimatch": { "version": "3.0.4", "bundled": true, "dev": true, "requires": { "brace-expansion": "1.1.7" } }, "minimist": { "version": "0.0.8", "bundled": true, "dev": true }, "mkdirp": { "version": "0.5.1", "bundled": true, "dev": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", "bundled": true, "dev": true, "optional": true }, "node-pre-gyp": { "version": "0.6.39", "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "1.0.2", "hawk": "3.1.3", "mkdirp": "0.5.1", "nopt": "4.0.1", "npmlog": "4.1.0", "rc": "1.2.1", "request": "2.81.0", "rimraf": "2.6.1", "semver": "5.3.0", "tar": "2.2.1", "tar-pack": "3.4.0" } }, "nopt": { "version": "4.0.1", "bundled": true, "dev": true, "optional": true, "requires": { "abbrev": "1.1.0", "osenv": "0.1.4" } }, "npmlog": { "version": "4.1.0", "bundled": true, "dev": true, "optional": true, "requires": { "are-we-there-yet": "1.1.4", "console-control-strings": "1.1.0", "gauge": "2.7.4", "set-blocking": "2.0.0" } }, "number-is-nan": { "version": "1.0.1", "bundled": true, "dev": true }, "oauth-sign": { "version": "0.8.2", "bundled": true, "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", "bundled": true, "dev": true, "optional": true }, "once": { "version": "1.4.0", "bundled": true, "dev": true, "requires": { "wrappy": "1.0.2" } }, "os-homedir": { "version": "1.0.2", "bundled": true, "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, "dev": true, "optional": true }, "osenv": { "version": "0.1.4", "bundled": true, "dev": true, "optional": true, "requires": { "os-homedir": "1.0.2", "os-tmpdir": "1.0.2" } }, "path-is-absolute": { "version": "1.0.1", "bundled": true, "dev": true }, "performance-now": { "version": "0.2.0", "bundled": true, "dev": true, "optional": true }, "process-nextick-args": { "version": "1.0.7", "bundled": true, "dev": true }, "punycode": { "version": "1.4.1", "bundled": true, "dev": true, "optional": true }, "qs": { "version": "6.4.0", "bundled": true, "dev": true, "optional": true }, "rc": { "version": "1.2.1", "bundled": true, "dev": true, "optional": true, "requires": { "deep-extend": "0.4.2", "ini": "1.3.4", "minimist": "1.2.0", "strip-json-comments": "2.0.1" }, "dependencies": { "minimist": { "version": "1.2.0", "bundled": true, "dev": true, "optional": true } } }, "readable-stream": { "version": "2.2.9", "bundled": true, "dev": true, "requires": { "buffer-shims": "1.0.0", "core-util-is": "1.0.2", "inherits": "2.0.3", "isarray": "1.0.0", "process-nextick-args": "1.0.7", "string_decoder": "1.0.1", "util-deprecate": "1.0.2" } }, "request": { "version": "2.81.0", "bundled": true, "dev": true, "optional": true, "requires": { "aws-sign2": "0.6.0", "aws4": "1.6.0", "caseless": "0.12.0", "combined-stream": "1.0.5", "extend": "3.0.1", "forever-agent": "0.6.1", "form-data": "2.1.4", "har-validator": "4.2.1", "hawk": "3.1.3", "http-signature": "1.1.1", "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", "mime-types": "2.1.15", "oauth-sign": "0.8.2", "performance-now": "0.2.0", "qs": "6.4.0", "safe-buffer": "5.0.1", "stringstream": "0.0.5", "tough-cookie": "2.3.2", "tunnel-agent": "0.6.0", "uuid": "3.0.1" } }, "rimraf": { "version": "2.6.1", "bundled": true, "dev": true, "requires": { "glob": "7.1.2" } }, "safe-buffer": { "version": "5.0.1", "bundled": true, "dev": true }, "semver": { "version": "5.3.0", "bundled": true, "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", "bundled": true, "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", "bundled": true, "dev": true, "optional": true }, "sntp": { "version": "1.0.9", "bundled": true, "dev": true, "requires": { "hoek": "2.16.3" } }, "sshpk": { "version": "1.13.0", "bundled": true, "dev": true, "optional": true, "requires": { "asn1": "0.2.3", "assert-plus": "1.0.0", "bcrypt-pbkdf": "1.0.1", "dashdash": "1.14.1", "ecc-jsbn": "0.1.1", "getpass": "0.1.7", "jodid25519": "1.0.2", "jsbn": "0.1.1", "tweetnacl": "0.14.5" }, "dependencies": { "assert-plus": { "version": "1.0.0", "bundled": true, "dev": true, "optional": true } } }, "string-width": { "version": "1.0.2", "bundled": true, "dev": true, "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", "strip-ansi": "3.0.1" } }, "string_decoder": { "version": "1.0.1", "bundled": true, "dev": true, "requires": { "safe-buffer": "5.0.1" } }, "stringstream": { "version": "0.0.5", "bundled": true, "dev": true, "optional": true }, "strip-ansi": { "version": "3.0.1", "bundled": true, "dev": true, "requires": { "ansi-regex": "2.1.1" } }, "strip-json-comments": { "version": "2.0.1", "bundled": true, "dev": true, "optional": true }, "tar": { "version": "2.2.1", "bundled": true, "dev": true, "requires": { "block-stream": "0.0.9", "fstream": "1.0.11", "inherits": "2.0.3" } }, "tar-pack": { "version": "3.4.0", "bundled": true, "dev": true, "optional": true, "requires": { "debug": "2.6.8", "fstream": "1.0.11", "fstream-ignore": "1.0.5", "once": "1.4.0", "readable-stream": "2.2.9", "rimraf": "2.6.1", "tar": "2.2.1", "uid-number": "0.0.6" } }, "tough-cookie": { "version": "2.3.2", "bundled": true, "dev": true, "optional": true, "requires": { "punycode": "1.4.1" } }, "tunnel-agent": { "version": "0.6.0", "bundled": true, "dev": true, "optional": true, "requires": { "safe-buffer": "5.0.1" } }, "tweetnacl": { "version": "0.14.5", "bundled": true, "dev": true, "optional": true }, "uid-number": { "version": "0.0.6", "bundled": true, "dev": true, "optional": true }, "util-deprecate": { "version": "1.0.2", "bundled": true, "dev": true }, "uuid": { "version": "3.0.1", "bundled": true, "dev": true, "optional": true }, "verror": { "version": "1.3.6", "bundled": true, "dev": true, "optional": true, "requires": { "extsprintf": "1.0.2" } }, "wide-align": { "version": "1.1.2", "bundled": true, "dev": true, "optional": true, "requires": { "string-width": "1.0.2" } }, "wrappy": { "version": "1.0.2", "bundled": true, "dev": true } } }, "generate-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", "dev": true }, "generate-object-property": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", "dev": true, "requires": { "is-property": "1.0.2" } }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "dev": true }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "dev": true, "requires": { "assert-plus": "1.0.0" }, "dependencies": { "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true } } }, "glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", "dev": true, "requires": { "inflight": "1.0.6", "inherits": "2.0.3", "minimatch": "3.0.4", "once": "1.4.0", "path-is-absolute": "1.0.1" } }, "glob-base": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "dev": true, "requires": { "glob-parent": "2.0.0", "is-glob": "2.0.1" } }, "glob-parent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, "requires": { "is-glob": "2.0.1" } }, "globals": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz", "integrity": "sha1-k9SmK9ysOM+vr8R9awNHaMsP/LQ=", "dev": true }, "globby": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", "dev": true, "requires": { "array-union": "1.0.2", "arrify": "1.0.1", "glob": "7.1.2", "object-assign": "4.1.1", "pify": "2.3.0", "pinkie-promise": "2.0.1" }, "dependencies": { "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.3", "minimatch": "3.0.4", "once": "1.4.0", "path-is-absolute": "1.0.1" } } } }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, "handlebars": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { "async": "1.5.2", "optimist": "0.6.1", "source-map": "0.4.4", "uglify-js": "2.8.29" } }, "har-validator": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", "dev": true, "requires": { "chalk": "1.1.3", "commander": "2.15.1", "is-my-json-valid": "2.17.2", "pinkie-promise": "2.0.1" } }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { "ansi-regex": "2.1.1" } }, "has-binary": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", "dev": true, "requires": { "isarray": "0.0.1" }, "dependencies": { "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true } } }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", "dev": true }, "has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", "dev": true }, "hasha": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", "dev": true, "requires": { "is-stream": "1.1.0", "pinkie-promise": "2.0.1" } }, "hawk": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", "dev": true, "requires": { "boom": "2.10.1", "cryptiles": "2.0.5", "hoek": "2.16.3", "sntp": "1.0.9" } }, "hoek": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", "dev": true }, "hosted-git-info": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", "dev": true }, "http-errors": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", "dev": true, "requires": { "depd": "1.1.1", "inherits": "2.0.3", "setprototypeof": "1.0.3", "statuses": "1.4.0" }, "dependencies": { "depd": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", "dev": true } } }, "http-proxy": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=", "dev": true, "requires": { "eventemitter3": "1.2.0", "requires-port": "1.0.0" } }, "http-signature": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", "dev": true, "requires": { "assert-plus": "0.2.0", "jsprim": "1.4.1", "sshpk": "1.14.1" } }, "iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", "dev": true }, "indent-string": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, "requires": { "repeating": "2.0.1" } }, "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { "once": "1.4.0", "wrappy": "1.0.2" } }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "inquirer": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.11.4.tgz", "integrity": "sha1-geM3ToNhvq/y2XAWIG01nQsy+k0=", "dev": true, "requires": { "ansi-escapes": "1.4.0", "ansi-regex": "2.1.1", "chalk": "1.1.3", "cli-cursor": "1.0.2", "cli-width": "1.1.1", "figures": "1.7.0", "lodash": "3.10.1", "readline2": "1.0.1", "run-async": "0.1.0", "rx-lite": "3.1.2", "string-width": "1.0.2", "strip-ansi": "3.0.1", "through": "2.3.8" } }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "dev": true, "requires": { "binary-extensions": "1.11.0" } }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-builtin-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { "builtin-modules": "1.1.1" } }, "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", "dev": true }, "is-equal-shallow": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "dev": true, "requires": { "is-primitive": "2.0.0" } }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", "dev": true }, "is-finite": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { "number-is-nan": "1.0.1" } }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { "number-is-nan": "1.0.1" } }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { "is-extglob": "1.0.0" } }, "is-my-ip-valid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", "dev": true }, "is-my-json-valid": { "version": "2.17.2", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", "dev": true, "requires": { "generate-function": "2.0.0", "generate-object-property": "1.2.0", "is-my-ip-valid": "1.0.0", "jsonpointer": "4.0.1", "xtend": "4.0.1" } }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { "kind-of": "3.2.2" } }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", "dev": true }, "is-path-in-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", "dev": true, "requires": { "is-path-inside": "1.0.1" } }, "is-path-inside": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "dev": true, "requires": { "path-is-inside": "1.0.2" } }, "is-posix-bracket": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", "dev": true }, "is-primitive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "dev": true }, "is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", "dev": true }, "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isbinaryfile": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, "requires": { "isarray": "1.0.0" } }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, "istanbul": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", "dev": true, "requires": { "abbrev": "1.0.9", "async": "1.5.2", "escodegen": "1.8.1", "esprima": "2.7.3", "glob": "5.0.15", "handlebars": "4.0.11", "js-yaml": "3.4.5", "mkdirp": "0.5.1", "nopt": "3.0.6", "once": "1.4.0", "resolve": "1.1.7", "supports-color": "3.2.3", "which": "1.3.0", "wordwrap": "1.0.0" }, "dependencies": { "esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", "dev": true }, "resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, "supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { "has-flag": "1.0.0" } }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true } } }, "jasmine-core": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.4.1.tgz", "integrity": "sha1-b4OrOg8WlRcizgfSBsdz1XzIOL4=", "dev": true }, "js-yaml": { "version": "3.4.5", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.5.tgz", "integrity": "sha1-w0A3l98SuRhmV08t4jZG/oyvtE0=", "dev": true, "requires": { "argparse": "1.0.10", "esprima": "2.7.3" }, "dependencies": { "esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", "dev": true } } }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true, "optional": true }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, "json-stable-stringify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "dev": true, "requires": { "jsonify": "0.0.0" } }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, "json3": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/json3/-/json3-3.2.6.tgz", "integrity": "sha1-9u/JPAagTemuxTBT3yVZuxniA4s=", "dev": true }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { "graceful-fs": "4.1.11" } }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "dev": true }, "jsonpointer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", "dev": true }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", "json-schema": "0.2.3", "verror": "1.10.0" }, "dependencies": { "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true } } }, "karma": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/karma/-/karma-1.1.2.tgz", "integrity": "sha1-eM0J4KfTghxiMpH9Hsm61al2PIU=", "dev": true, "requires": { "bluebird": "3.5.1", "body-parser": "1.18.2", "chokidar": "1.7.0", "colors": "1.2.1", "combine-lists": "1.0.1", "connect": "3.6.6", "core-js": "2.5.3", "di": "0.0.1", "dom-serialize": "2.2.1", "expand-braces": "0.1.2", "glob": "7.1.2", "graceful-fs": "4.1.11", "http-proxy": "1.16.2", "isbinaryfile": "3.0.2", "lodash": "3.10.1", "log4js": "0.6.38", "mime": "1.6.0", "minimatch": "3.0.4", "optimist": "0.6.1", "qjobs": "1.2.0", "rimraf": "2.6.2", "socket.io": "1.4.7", "source-map": "0.5.7", "tmp": "0.0.28", "useragent": "2.3.0" }, "dependencies": { "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.3", "minimatch": "3.0.4", "once": "1.4.0", "path-is-absolute": "1.0.1" } }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true } } }, "karma-chrome-launcher": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-1.0.1.tgz", "integrity": "sha1-vlrnxCZPmgouIuPZhL6zJa2SyMs=", "dev": true, "requires": { "fs-access": "1.0.1", "which": "1.3.0" } }, "karma-cli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/karma-cli/-/karma-cli-1.0.1.tgz", "integrity": "sha1-rmw8WKMTodALRRZMRVubhs4X+WA=", "dev": true, "requires": { "resolve": "1.6.0" } }, "karma-coverage": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-1.1.1.tgz", "integrity": "sha1-Wv+LOc9plNwi3kyENix2ABtjfPY=", "dev": true, "requires": { "dateformat": "1.0.12", "istanbul": "0.4.5", "lodash": "3.10.1", "minimatch": "3.0.4", "source-map": "0.5.7" }, "dependencies": { "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true } } }, "karma-jasmine": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.0.2.tgz", "integrity": "sha1-wLOrMnvyB9tg4X+ifbN8/e9djmw=", "dev": true }, "karma-ng-html2js-preprocessor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/karma-ng-html2js-preprocessor/-/karma-ng-html2js-preprocessor-1.0.0.tgz", "integrity": "sha1-ENjIz6pBNvHIp22RpMvO7evsSjE=", "dev": true }, "karma-phantomjs-launcher": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz", "integrity": "sha1-0jyjSAG9qYY60xjju0vUBisTrNI=", "dev": true, "requires": { "lodash": "4.17.5", "phantomjs-prebuilt": "2.1.14" }, "dependencies": { "lodash": { "version": "4.17.5", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", "dev": true } } }, "karma-threshold-reporter": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/karma-threshold-reporter/-/karma-threshold-reporter-0.1.15.tgz", "integrity": "sha1-tLnz8Go+Aj0qE2BwP5Dwm5sE4PE=", "dev": true, "requires": { "istanbul": "0.3.22" }, "dependencies": { "escodegen": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz", "integrity": "sha1-MOz89mypjcZ80v0WKr626vqM5vw=", "dev": true, "requires": { "esprima": "1.2.5", "estraverse": "1.9.3", "esutils": "2.0.2", "optionator": "0.5.0", "source-map": "0.2.0" }, "dependencies": { "esprima": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", "integrity": "sha1-CZNQL+r2aBODJXVvMPmlH+7sEek=", "dev": true } } }, "esprima": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz", "integrity": "sha1-84ekb9NEwbGjm6+MIL+0O20AWMw=", "dev": true }, "estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", "dev": true }, "istanbul": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz", "integrity": "sha1-PhZNhQIf4ZyYXR8OfvDD4i0BLrY=", "dev": true, "requires": { "abbrev": "1.0.9", "async": "1.5.2", "escodegen": "1.7.1", "esprima": "2.5.0", "fileset": "0.2.1", "handlebars": "4.0.11", "js-yaml": "3.4.5", "mkdirp": "0.5.1", "nopt": "3.0.6", "once": "1.4.0", "resolve": "1.1.7", "supports-color": "3.2.3", "which": "1.3.0", "wordwrap": "1.0.0" } }, "optionator": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz", "integrity": "sha1-t1qJlaLUF98ltuTjhi9QqohlE2g=", "dev": true, "requires": { "deep-is": "0.1.3", "fast-levenshtein": "1.0.7", "levn": "0.2.5", "prelude-ls": "1.1.2", "type-check": "0.3.2", "wordwrap": "0.0.3" }, "dependencies": { "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true } } }, "resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, "source-map": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "dev": true, "optional": true, "requires": { "amdefine": "1.0.1" } }, "supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { "has-flag": "1.0.0" } }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true } } }, "kew": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", "dev": true }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "1.1.6" } }, "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, "requires": { "graceful-fs": "4.1.11" } }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "dev": true, "optional": true }, "levn": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz", "integrity": "sha1-uo0znQykphDjo/FFucr0iAcVUFQ=", "dev": true, "requires": { "prelude-ls": "1.1.2", "type-check": "0.3.2" } }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { "graceful-fs": "4.1.11", "parse-json": "2.2.0", "pify": "2.3.0", "pinkie-promise": "2.0.1", "strip-bom": "2.0.0" } }, "lodash": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", "dev": true }, "lodash._arraycopy": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", "integrity": "sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE=", "dev": true }, "lodash._arrayeach": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", "integrity": "sha1-urFWsqkNPxu9XGU0AzSeXlkz754=", "dev": true }, "lodash._arraymap": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz", "integrity": "sha1-Go/Q9MDfS2HeoHbXF83Jfwo8PmY=", "dev": true }, "lodash._baseassign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", "dev": true, "requires": { "lodash._basecopy": "3.0.1", "lodash.keys": "3.1.2" } }, "lodash._baseclone": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", "integrity": "sha1-MDUZv2OT/n5C802LYw73eU41Qrc=", "dev": true, "requires": { "lodash._arraycopy": "3.0.0", "lodash._arrayeach": "3.0.0", "lodash._baseassign": "3.2.0", "lodash._basefor": "3.0.3", "lodash.isarray": "3.0.4", "lodash.keys": "3.1.2" } }, "lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", "dev": true }, "lodash._basedifference": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz", "integrity": "sha1-8sIEKWwqeOArOJCBtu3KyTPPYpw=", "dev": true, "requires": { "lodash._baseindexof": "3.1.0", "lodash._cacheindexof": "3.0.2", "lodash._createcache": "3.1.2" } }, "lodash._baseflatten": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz", "integrity": "sha1-B3D/gBMa9uNPO1EXlqe6UhTmX/c=", "dev": true, "requires": { "lodash.isarguments": "3.1.0", "lodash.isarray": "3.0.4" } }, "lodash._basefor": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=", "dev": true }, "lodash._baseindexof": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=", "dev": true }, "lodash._bindcallback": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", "dev": true }, "lodash._cacheindexof": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=", "dev": true }, "lodash._createassigner": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", "integrity": "sha1-g4pbri/aymOsIt7o4Z+k5taXCxE=", "dev": true, "requires": { "lodash._bindcallback": "3.0.1", "lodash._isiterateecall": "3.0.9", "lodash.restparam": "3.6.1" } }, "lodash._createcache": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=", "dev": true, "requires": { "lodash._getnative": "3.9.1" } }, "lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", "dev": true }, "lodash._isiterateecall": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", "dev": true }, "lodash._pickbyarray": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz", "integrity": "sha1-H4mNlgfrVgsOFnOEt3x8bRCKpMU=", "dev": true }, "lodash._pickbycallback": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz", "integrity": "sha1-/2G5oBens699MObFPeKK+hm4dQo=", "dev": true, "requires": { "lodash._basefor": "3.0.3", "lodash.keysin": "3.0.8" } }, "lodash.clonedeep": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", "integrity": "sha1-oKHkDYKl6on/WxR7hETtY9koJ9s=", "dev": true, "requires": { "lodash._baseclone": "3.3.0", "lodash._bindcallback": "3.0.1" } }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", "dev": true }, "lodash.isarray": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", "dev": true }, "lodash.isplainobject": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", "integrity": "sha1-moI4rhayAEMpYM1zRlEtASP79MU=", "dev": true, "requires": { "lodash._basefor": "3.0.3", "lodash.isarguments": "3.1.0", "lodash.keysin": "3.0.8" } }, "lodash.istypedarray": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz", "integrity": "sha1-yaR3SYYHUB2OhJTSg7h8OSgc72I=", "dev": true }, "lodash.keys": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { "lodash._getnative": "3.9.1", "lodash.isarguments": "3.1.0", "lodash.isarray": "3.0.4" } }, "lodash.keysin": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", "integrity": "sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8=", "dev": true, "requires": { "lodash.isarguments": "3.1.0", "lodash.isarray": "3.0.4" } }, "lodash.merge": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz", "integrity": "sha1-DZDZPtY3sYeEN7s+IWASYNev6ZQ=", "dev": true, "requires": { "lodash._arraycopy": "3.0.0", "lodash._arrayeach": "3.0.0", "lodash._createassigner": "3.1.1", "lodash._getnative": "3.9.1", "lodash.isarguments": "3.1.0", "lodash.isarray": "3.0.4", "lodash.isplainobject": "3.2.0", "lodash.istypedarray": "3.0.6", "lodash.keys": "3.1.2", "lodash.keysin": "3.0.8", "lodash.toplainobject": "3.0.0" } }, "lodash.omit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-3.1.0.tgz", "integrity": "sha1-iX/jguZBPZrJfGH3jtHgV6AK+fM=", "dev": true, "requires": { "lodash._arraymap": "3.0.0", "lodash._basedifference": "3.0.3", "lodash._baseflatten": "3.1.4", "lodash._bindcallback": "3.0.1", "lodash._pickbyarray": "3.0.2", "lodash._pickbycallback": "3.0.0", "lodash.keysin": "3.0.8", "lodash.restparam": "3.6.1" } }, "lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", "dev": true }, "lodash.toplainobject": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz", "integrity": "sha1-KHkK2ULSk9eKpmOgfs9/UsoEGY0=", "dev": true, "requires": { "lodash._basecopy": "3.0.1", "lodash.keysin": "3.0.8" } }, "log4js": { "version": "0.6.38", "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=", "dev": true, "requires": { "readable-stream": "1.0.34", "semver": "4.3.6" }, "dependencies": { "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, "readable-stream": { "version": "1.0.34", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", "isarray": "0.0.1", "string_decoder": "0.10.31" } }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true } } }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "dev": true, "requires": { "currently-unhandled": "0.4.1", "signal-exit": "3.0.2" } }, "lru-cache": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", "dev": true, "requires": { "pseudomap": "1.0.2", "yallist": "2.1.2" } }, "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, "meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { "camelcase-keys": "2.1.0", "decamelize": "1.2.0", "loud-rejection": "1.6.0", "map-obj": "1.0.1", "minimist": "1.2.0", "normalize-package-data": "2.4.0", "object-assign": "4.1.1", "read-pkg-up": "1.0.1", "redent": "1.0.0", "trim-newlines": "1.0.0" }, "dependencies": { "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } } }, "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { "arr-diff": "2.0.0", "array-unique": "0.2.1", "braces": "1.8.5", "expand-brackets": "0.1.5", "extglob": "0.3.2", "filename-regex": "2.0.1", "is-extglob": "1.0.0", "is-glob": "2.0.1", "kind-of": "3.2.2", "normalize-path": "2.1.1", "object.omit": "2.0.1", "parse-glob": "3.0.4", "regex-cache": "0.4.4" } }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", "dev": true }, "mime-types": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "requires": { "mime-db": "1.33.0" } }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "1.1.11" } }, "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "mute-stream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", "dev": true }, "nan": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", "dev": true, "optional": true }, "negotiator": { "version": "0.4.9", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.9.tgz", "integrity": "sha1-kuRrbbU8fkIe1koryU8IvnYw3z8=", "dev": true }, "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { "abbrev": "1.0.9" } }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { "hosted-git-info": "2.6.0", "is-builtin-module": "1.0.0", "semver": "4.3.6", "validate-npm-package-license": "3.0.3" } }, "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { "remove-trailing-separator": "1.1.0" } }, "null-check": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", "dev": true }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", "dev": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, "object-component": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", "dev": true }, "object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, "requires": { "for-own": "0.1.5", "is-extendable": "0.1.1" } }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", "dev": true, "requires": { "ee-first": "1.1.1" } }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1.0.2" } }, "onetime": { "version": "1.1.0", "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", "dev": true }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { "minimist": "0.0.8", "wordwrap": "0.0.3" } }, "optionator": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.6.0.tgz", "integrity": "sha1-tj7Lvw4xX61LyYJ7Rdx7pFKE/LY=", "dev": true, "requires": { "deep-is": "0.1.3", "fast-levenshtein": "1.0.7", "levn": "0.2.5", "prelude-ls": "1.1.2", "type-check": "0.3.2", "wordwrap": "0.0.3" } }, "options": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", "dev": true }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, "parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "dev": true, "requires": { "glob-base": "0.3.0", "is-dotfile": "1.0.3", "is-extglob": "1.0.0", "is-glob": "2.0.1" } }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { "error-ex": "1.3.1" } }, "parsejson": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.1.tgz", "integrity": "sha1-mxDGwNglq1ieaFFTgm3go7oni8w=", "dev": true, "requires": { "better-assert": "1.0.2" } }, "parseqs": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.2.tgz", "integrity": "sha1-nf5wss3aw4i95PNbHyQPpYrb5sc=", "dev": true, "requires": { "better-assert": "1.0.2" } }, "parseuri": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.4.tgz", "integrity": "sha1-gGWCo5iH4eoY3V4v4OAZAiaOk1A=", "dev": true, "requires": { "better-assert": "1.0.2" } }, "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", "dev": true }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { "pinkie-promise": "2.0.1" } }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, "path-parse": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { "graceful-fs": "4.1.11", "pify": "2.3.0", "pinkie-promise": "2.0.1" } }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "dev": true }, "phantomjs-prebuilt": { "version": "2.1.14", "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz", "integrity": "sha1-1T0xH8+30dCN2yQBRVjxGIxRbaA=", "dev": true, "requires": { "es6-promise": "4.0.5", "extract-zip": "1.5.0", "fs-extra": "1.0.0", "hasha": "2.2.0", "kew": "0.7.0", "progress": "1.1.8", "request": "2.79.0", "request-progress": "2.0.1", "which": "1.2.14" }, "dependencies": { "which": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", "dev": true, "requires": { "isexe": "2.0.0" } } } }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { "pinkie": "2.0.4" } }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", "dev": true }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, "progress": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true }, "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true }, "qs": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", "dev": true }, "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, "requires": { "is-number": "3.0.0", "kind-of": "4.0.0" }, "dependencies": { "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { "kind-of": "3.2.2" }, "dependencies": { "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "1.1.6" } } } }, "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { "is-buffer": "1.1.6" } } } }, "raw-body": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", "dev": true, "requires": { "bytes": "3.0.0", "http-errors": "1.6.2", "iconv-lite": "0.4.19", "unpipe": "1.0.0" } }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { "load-json-file": "1.1.0", "normalize-package-data": "2.4.0", "path-type": "1.1.0" } }, "read-pkg-up": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { "find-up": "1.1.2", "read-pkg": "1.1.0" } }, "readable-stream": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", "dev": true, "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", "isarray": "1.0.0", "process-nextick-args": "2.0.0", "safe-buffer": "5.1.1", "string_decoder": "1.0.3", "util-deprecate": "1.0.2" } }, "readdirp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", "dev": true, "requires": { "graceful-fs": "4.1.11", "minimatch": "3.0.4", "readable-stream": "2.3.5", "set-immediate-shim": "1.0.1" } }, "readline2": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", "dev": true, "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", "mute-stream": "0.0.5" } }, "redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "dev": true, "requires": { "indent-string": "2.1.0", "strip-indent": "1.0.1" } }, "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { "is-equal-shallow": "0.1.3" } }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", "dev": true }, "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", "dev": true }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { "is-finite": "1.0.2" } }, "request": { "version": "2.79.0", "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", "dev": true, "requires": { "aws-sign2": "0.6.0", "aws4": "1.6.0", "caseless": "0.11.0", "combined-stream": "1.0.6", "extend": "3.0.1", "forever-agent": "0.6.1", "form-data": "2.1.4", "har-validator": "2.0.6", "hawk": "3.1.3", "http-signature": "1.1.1", "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", "mime-types": "2.1.18", "oauth-sign": "0.8.2", "qs": "6.3.2", "stringstream": "0.0.5", "tough-cookie": "2.3.4", "tunnel-agent": "0.4.3", "uuid": "3.2.1" }, "dependencies": { "qs": { "version": "6.3.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", "dev": true } } }, "request-progress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", "dev": true, "requires": { "throttleit": "1.0.0" } }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, "resolve": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz", "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==", "dev": true, "requires": { "path-parse": "1.0.5" } }, "restore-cursor": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", "dev": true, "requires": { "exit-hook": "1.1.1", "onetime": "1.1.0" } }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, "optional": true, "requires": { "align-text": "0.1.4" } }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { "glob": "7.1.2" }, "dependencies": { "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.3", "minimatch": "3.0.4", "once": "1.4.0", "path-is-absolute": "1.0.1" } } } }, "run-async": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", "dev": true, "requires": { "once": "1.4.0" } }, "rx-lite": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", "dev": true }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true }, "semver": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", "dev": true }, "set-immediate-shim": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", "dev": true }, "setprototypeof": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", "dev": true }, "shelljs": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz", "integrity": "sha1-xUmCuZbHbvDB5rWfvcWCX1txMRM=", "dev": true }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "sntp": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", "dev": true, "requires": { "hoek": "2.16.3" } }, "socket.io": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.4.7.tgz", "integrity": "sha1-krf3y4jFeX1NruJ5/oB12+bT+hw=", "dev": true, "requires": { "debug": "2.2.0", "engine.io": "1.6.10", "has-binary": "0.1.7", "socket.io-adapter": "0.4.0", "socket.io-client": "1.4.6", "socket.io-parser": "2.2.6" }, "dependencies": { "debug": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", "dev": true, "requires": { "ms": "0.7.1" } }, "ms": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", "dev": true } } }, "socket.io-adapter": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.4.0.tgz", "integrity": "sha1-+5+CqxqmUpC/csNleVW5MKmRok8=", "dev": true, "requires": { "debug": "2.2.0", "socket.io-parser": "2.2.2" }, "dependencies": { "debug": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", "dev": true, "requires": { "ms": "0.7.1" } }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, "ms": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", "dev": true }, "socket.io-parser": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.2.tgz", "integrity": "sha1-PXr2tkSX6Va32f53X5mXFgJ/lBc=", "dev": true, "requires": { "benchmark": "1.0.0", "component-emitter": "1.1.2", "debug": "0.7.4", "isarray": "0.0.1", "json3": "3.2.6" }, "dependencies": { "debug": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", "dev": true } } } } }, "socket.io-client": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.4.6.tgz", "integrity": "sha1-SbC6U379FbgpfIQBbmQuHHx1LD0=", "dev": true, "requires": { "backo2": "1.0.2", "component-bind": "1.0.0", "component-emitter": "1.2.0", "debug": "2.2.0", "engine.io-client": "1.6.9", "has-binary": "0.1.7", "indexof": "0.0.1", "object-component": "0.0.3", "parseuri": "0.0.4", "socket.io-parser": "2.2.6", "to-array": "0.1.4" }, "dependencies": { "component-emitter": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.0.tgz", "integrity": "sha1-zNETqGOI0GSC0D3j/H35hSa6jv4=", "dev": true }, "debug": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", "dev": true, "requires": { "ms": "0.7.1" } }, "ms": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", "dev": true } } }, "socket.io-parser": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.6.tgz", "integrity": "sha1-ON/WHfUNz4qx2eIJEyK/kCuii5k=", "dev": true, "requires": { "benchmark": "1.0.0", "component-emitter": "1.1.2", "debug": "2.2.0", "isarray": "0.0.1", "json3": "3.3.2" }, "dependencies": { "debug": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", "dev": true, "requires": { "ms": "0.7.1" } }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, "json3": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", "dev": true }, "ms": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", "dev": true } } }, "source-map": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { "amdefine": "1.0.1" } }, "spdx-correct": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "dev": true, "requires": { "spdx-expression-parse": "3.0.0", "spdx-license-ids": "3.0.0" } }, "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { "spdx-exceptions": "2.1.0", "spdx-license-ids": "3.0.0" } }, "spdx-license-ids": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", "dev": true }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, "sshpk": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", "dev": true, "requires": { "asn1": "0.2.3", "assert-plus": "1.0.0", "bcrypt-pbkdf": "1.0.1", "dashdash": "1.14.1", "ecc-jsbn": "0.1.1", "getpass": "0.1.7", "jsbn": "0.1.1", "tweetnacl": "0.14.5" }, "dependencies": { "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true } } }, "statuses": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", "dev": true }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", "strip-ansi": "3.0.1" } }, "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true, "requires": { "safe-buffer": "5.1.1" } }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", "dev": true }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "2.1.1" } }, "strip-bom": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { "is-utf8": "0.2.1" } }, "strip-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "dev": true, "requires": { "get-stdin": "4.0.1" } }, "strip-json-comments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", "dev": true }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", "dev": true }, "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, "tmp": { "version": "0.0.28", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz", "integrity": "sha1-Fyc1t/YU6nrzlmT6hM8N5OUV0SA=", "dev": true, "requires": { "os-tmpdir": "1.0.2" } }, "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", "dev": true }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "dev": true, "requires": { "punycode": "1.4.1" } }, "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true }, "tunnel-agent": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", "dev": true }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true, "optional": true }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { "prelude-ls": "1.1.2" } }, "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "dev": true, "requires": { "media-typer": "0.3.0", "mime-types": "2.1.18" } }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, "requires": { "source-map": "0.5.7", "uglify-to-browserify": "1.0.2", "yargs": "3.10.0" }, "dependencies": { "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true, "optional": true } } }, "uglify-to-browserify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true, "optional": true }, "ultron": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", "dev": true }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, "user-home": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", "dev": true, "requires": { "os-homedir": "1.0.2" } }, "useragent": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", "dev": true, "requires": { "lru-cache": "4.1.2", "tmp": "0.0.28" } }, "utf8": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.0.tgz", "integrity": "sha1-DP7FyAUtRKI+OqqQgQToB1+V39U=", "dev": true }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true }, "uuid": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", "dev": true }, "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", "dev": true, "requires": { "spdx-correct": "3.0.0", "spdx-expression-parse": "3.0.0" } }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { "assert-plus": "1.0.0", "core-util-is": "1.0.2", "extsprintf": "1.3.0" }, "dependencies": { "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true } } }, "void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { "isexe": "2.0.0" } }, "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true, "optional": true }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", "dev": true, "requires": { "mkdirp": "0.5.1" } }, "ws": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ws/-/ws-1.0.1.tgz", "integrity": "sha1-fQsqLljN3YGQOcKcneZQReGzEOk=", "dev": true, "requires": { "options": "0.0.6", "ultron": "1.0.2" } }, "xml-escape": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz", "integrity": "sha1-AJY9aXsq3wwYXE4E5zF0upsojrI=", "dev": true }, "xmlhttprequest-ssl": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.1.tgz", "integrity": "sha1-O3dB/qSoZnWXbpCNKW1ERZYfqmc=", "dev": true }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "optional": true, "requires": { "camelcase": "1.2.1", "cliui": "2.1.0", "decamelize": "1.2.0", "window-size": "0.1.0" } }, "yauzl": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", "dev": true, "requires": { "fd-slicer": "1.0.1" } }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", "dev": true } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/package.json0000664000175100017510000000210415033037474017473 0ustar00mylesmyles{ "version": "1.0.0", "private": true, "name": "octavia-dashboard", "description": "Octavia Dashboard", "homepage": "https://docs.openstack.org/octavia-dashboard/latest/", "keywords": [ "OpenStack", "octavia", "octavia-dashboard", "load-balancer" ], "repository": { "type": "git", "url": "https://opendev.org/openstack/octavia-dashboard" }, "bugs": "https://storyboard.openstack.org/#!/project/909", "license": "Apache 2.0", "devDependencies": { "eslint": "3.0.0", "eslint-config-openstack": "4.0.1", "eslint-plugin-angular": "4.0.1", "jasmine-core": "3.6.0", "karma": "5.2.3", "karma-firefox-launcher": "2.1.0", "karma-cli": "2.0.0", "karma-coverage": "2.0.3", "karma-jasmine": "4.0.1", "karma-ng-html2js-preprocessor": "1.0.0", "karma-threshold-reporter": "0.1.15" }, "scripts": { "postinstall": "octavia_dashboard/post_install.sh", "test": "karma start octavia_dashboard/karma.conf.js --single-run", "lint": "eslint --no-color octavia_dashboard/static" }, "dependencies": {} } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.460101 octavia_dashboard-15.1.0.dev2/releasenotes/0000775000175100017510000000000015033037476017703 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4761007 octavia_dashboard-15.1.0.dev2/releasenotes/notes/0000775000175100017510000000000015033037476021033 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/Add-ProxyV2-b5537c092737fe41.yaml0000664000175100017510000000012615033037474026015 0ustar00mylesmyles--- features: - | Added Octavia dashboard support for proxy protocol version 2. ././@PaxHeader0000000000000000000000000000021700000000000010215 xustar00121 path=octavia_dashboard-15.1.0.dev2/releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba0740000664000175100017510000000012115033037474032046 0ustar00mylesmyles--- fixes: - | Fixes a namespace collision with the barbican-ui dashboard. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-RBAC-43ee180e712294ed.yaml0000664000175100017510000000132215033037474025306 0ustar00mylesmyles--- features: - | Adds RBAC support to the dashboard panels. upgrade: - | To enable RBAC support in the Octavia dashboard you need to install the generated octavia_dashboard/conf/octavia_policy.yaml file into your horizon openstack_dashboard/conf/ directory and also copy octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py file into your horizon openstack_dashboard/local/local_settings.d/ directory. security: - | RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC in the dashboard or not, the API RBAC will still be in effect. Enabling RBAC in the dashboard will enforce the policies in the dashboard before the API call is made. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-allowed-cidrs-ad205b1524da3d2c.yaml0000664000175100017510000000011715033037474027443 0ustar00mylesmyles--- features: - | Add the ability to set allowed_cidrs on the listeners ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-az-support-efdd4e7c5dccef21.yaml0000664000175100017510000000014415033037474027366 0ustar00mylesmyles--- features: - | Added support for availability zones. Can now create a LB in a specific AZ. ././@PaxHeader0000000000000000000000000000022200000000000010211 xustar00124 path=octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-ciphers-options-for-listeners-and-pools-8440eaf5a551c44c.yaml 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-ciphers-options-for-listeners-and-pools-8440eaf0000664000175100017510000000021015033037474032356 0ustar00mylesmyles--- features: - | Added option to specify TLS ciphers for listeners and pools. The ciphers are represented in OpenSSL syntax. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml0000664000175100017510000000012315033037474031700 0ustar00mylesmyles--- fixes: - | Draining state was missing from the list of operating states. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-insert-headers-a6fd80c837a89536.yaml0000664000175100017510000000012415033037474027530 0ustar00mylesmyles--- features: - | Adds the ability to set the insertion headers on listeners. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml0000664000175100017510000000010115033037474026631 0ustar00mylesmyles--- features: - | Adds L7 policy support to the dashboard. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-member-backup-32e2ec2553c1ba24.yaml0000664000175100017510000000010215033037474027343 0ustar00mylesmyles--- features: - | Adds the ability to set member as backup. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-sctp-support-a1ea956b7630f47d.yaml0000664000175100017510000000014415033037474027345 0ustar00mylesmyles--- features: - | Add SCTP support in listener protocol and health-monitor type select boxes. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-timeout-options-8988fc477fa46d31.yaml0000664000175100017510000000012615033037474030003 0ustar00mylesmyles--- features: - | Adds the ability to set the timeout options on listeners. ././@PaxHeader0000000000000000000000000000021000000000000010206 xustar00114 path=octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-tls_enabled-support-for-pools-449e39f851535839.yaml 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-tls_enabled-support-for-pools-449e39f851535839.0000664000175100017510000000024415033037474031430 0ustar00mylesmyles--- features: - | Add TLS Enabled switch in the pool control form, allowing to enable/disable TLS communications between a load balancer and its members. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-udp-support-acb1a22fb605d3a8.yaml0000664000175100017510000000020615033037474027277 0ustar00mylesmyles--- features: - | Added UDP protocol support in listeners and pools, added UDP-CONNECT method for health-monitor resources. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/add-x-forwarded-proto-e30b52a3f853ed62.yaml0000664000175100017510000000015115033037474030234 0ustar00mylesmyles--- features: - | Adds the ability to set the X-Forwarded-Proto insertion header on listeners. ././@PaxHeader0000000000000000000000000000021200000000000010210 xustar00116 path=octavia_dashboard-15.1.0.dev2/releasenotes/notes/allows-creation-of-single-resources-9ec5fe87acc7c93c.yaml 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/allows-creation-of-single-resources-9ec5fe87acc7c930000664000175100017510000000041415033037474032261 0ustar00mylesmyles--- fixes: - | Allows the creation of single resources (i.e Load Balancer) without enforcing the creation of children resources (Listeners, Pools, Health monitors). A switch has been added in the children resource wizards to avoid resource creation. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/auto-refresh-detail-pages-26166d5d9c26edee.yaml0000664000175100017510000000012315033037474031160 0ustar00mylesmyles--- features: - | Adds the ability to auto refresh detail pages upon action. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml0000664000175100017510000000160515033037474030247 0ustar00mylesmyles--- features: - A new dashboard wizard for Octavia. Allows you to create an Octavia load balancer and related resources such as a listener, pool, pool members, and health monitor. - A view of all the existing Octavia load balancers. - Ability to view details of a Octavia load balancer and drill down to see details for the listener, pool, pool member, and health monitor resources. - Ability to create, update, and delete the Octavia load balancer, listener, pool, pool member, and health monitor resources. - Ability to associate and disassociate floating IP addresses for a load balancer. - Ability to choose from SSL certificates stored by the key-manager service when creating a listener using the TERMINATED_HTTPS protocol. - Ability to choose from existing instances from the compute service or specify external members when adding members to a pool. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/cascade-delete-e4c9d80a31076540.yaml0000664000175100017510000000030115033037474026603 0ustar00mylesmyles--- features: - | Allow cascade deletion of load balancer. other: - | This changed the default behavior of load balancer deletion from non-cascade deletion to cascade deletion. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/drop-py-2-7-f3372b5c26171513.yaml0000664000175100017510000000033315033037474025577 0ustar00mylesmyles--- upgrade: - | Python 2.7 support has been dropped. Last release of octavia-dashboard to support py2.7 is OpenStack Train. The minimum version of Python now supported by octavia-dashboard is Python 3.6. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/edit-default-pool-on-listener-206d8dfeea135360.yaml0000664000175100017510000000011215033037474031672 0ustar00mylesmyles--- features: - | You can now change the default pool on listeners. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/filter-select-65160dcbe699a96d.yaml0000664000175100017510000000061115033037474026706 0ustar00mylesmyles--- features: - | Adds a new UI component which works as a standard select control alternative. Options in the component are presented in a table which may be filtered using the select input field. Filtering is done across all table fields. upgrade: - | The new component replaces the standard select for subnet selection in the Load Balancer creation modal wizard.././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/fix-auth-issue-5226777261765699.yaml0000664000175100017510000000021415033037474026371 0ustar00mylesmyles--- fixes: - | Fixed an authentication issue with the OpenStack services. The dashboard could not get the list of load balancers. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml0000664000175100017510000000012315033037474031445 0ustar00mylesmyles--- fixes: - Fixed an issue where TERMINATED_HTTPS listener type was greyed out. ././@PaxHeader0000000000000000000000000000021100000000000010207 xustar00115 path=octavia_dashboard-15.1.0.dev2/releasenotes/notes/fix-certificate-list-listener-edit-1d9775d23692c34b.yaml 22 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/fix-certificate-list-listener-edit-1d9775d23692c34b0000664000175100017510000000021115033037474031617 0ustar00mylesmyles--- fixes: - | Fix a bug that prevented to display the ``default_tls_container_ref`` when editing an HTTP_TERMINATED listener. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml0000664000175100017510000000031315033037474030547 0ustar00mylesmyles--- fixes: - | Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/fix-flavor-no-flavor-profile-c3e82325f16d5ab8.yaml0000664000175100017510000000043015033037474031543 0ustar00mylesmyles--- fixes: - | Fixes an issue in the Octavia dashboard where users receive a 403 error when attempting to create a load balancer. This was due to the dashboard attempting to access the flavor profile information which is an administrator only object by default. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/fix-incorrect-region-endpoint-1afc5ebdc6fc4110.yaml0000664000175100017510000000025415033037474032211 0ustar00mylesmyles--- fixes: - | Fixed a bug when using multi-region deployments, the octavia-dashboard may have used the wrong keystone catalog to get the load-balancer endpoint. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml0000664000175100017510000000036715033037474031465 0ustar00mylesmyles--- fixes: - | Octavia supports setting the weight of members from 0 to 256, but in Horizon the value 0 was not accepted. This fix allows entering the value 0 as well, which is important for putting a member into DRAINING state. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml0000664000175100017510000000015015033037474030306 0ustar00mylesmyles--- fixes: - | Fix a bug that prevented the update of non-HTTP and non-HTTPS health monitors. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/flavor-support-0195a486faa16b7f.yaml0000664000175100017510000000022515033037474027134 0ustar00mylesmyles--- features: - | Add load balancer flavor support. issues: - | The octavia-dashboard requires openstacksdk > 0.24.0 for flavor support. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml0000664000175100017510000000341615033037474031003 0ustar00mylesmyles--- prelude: > The Octavia team is excited to release the 1.0.0 version of the Octavia dashboard. This dashboard uses the Octavia API endpoint via the openstacksdk. This release includes a number of improvements over the old neutron-lbaas-dashboard that worked against the neutron API endpoint. These improvements are listed below in the features section of this release note. features: - | The object details pages now use a tabbed navigation for child objects. - | Provisioning and operating status is now available on all object details pages. - | Pools can now change the load balancing algorithm after creation. - | Members now display the subnet_id on the details page. - | Health monitors can now change the expected HTTP codes. - | The session persistence for a pool can now be changed. - | Created at and Updated at times are now visible on the details pages. - | Health monitors can now use alternate IP addresses and ports. - | Listener connection limits can now be updated. - | All objects now allow setting the "Admin State". issues: - | The octavia-dashboard requires openstacksdk >= 0.10.0 to resolve an issue with displaying the health monitor details page. It is expected this will be included in the OpenStack Queens release. upgrade: - | This dashboard can be used alongside the neutron-lbaas-dashboard, but both dashboard panels will use the "Load Balancer" labels. other: - | The neutron-lbaas neutron extension is not required to use this dashboard. Load balancers created with neutron-lbaas that have not been migrated to Octavia may not be accessible via this dashboard. Only resources accessible via the Octavia API will be visible in this dashboard. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/list-pools-on-lb-details-page-eb0400bdb2b3650f.yaml0000664000175100017510000000016015033037474031631 0ustar00mylesmyles--- features: - | Pools attached to a load balancer are now listed on the load balancer details page. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/move-to-python-3.8-86095fce6076fb37.yaml0000664000175100017510000000027615033037474027311 0ustar00mylesmyles--- upgrade: - | Update Python base version from 3.6 to 3.8. As per Openstack Python runtime versions policy Python 3.8 is the minimum Python version in the Zed release cycle. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/pool-selection-hint-7f282ba1fa014d8c.yaml0000664000175100017510000000016215033037474030075 0ustar00mylesmyles--- features: - | The pool name is now visible in pool selection drop downs in addition to the pool ID. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/remove-barbicanclient-6b48fcc36afafb62.yaml0000664000175100017510000000033415033037474030606 0ustar00mylesmyles--- fixes: - | Barbicanclient caused an error when getting secrets. By replacing the code by OpenstackSDK this issue was fixed and the barbicanclient dependency could be dropped from the Octavia Dashboard. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924542.0 octavia_dashboard-15.1.0.dev2/releasenotes/notes/reno.cache0000664000175100017510000006222515033037476022772 0ustar00mylesmyles--- dates: - date: 1534874997 version: 2.0.0.0rc2 - date: 1631790025 version: 8.0.0.0rc1 - date: 1602670847 version: 6.0.0 - date: 1602147321 version: 6.0.0.0rc2 - date: 1595522317 version: rocky-eol - date: 1518100407 version: 1.0.0.0rc1 - date: 1570718283 version: 4.0.0.0rc2 - date: 1637052344 version: 5.0.2 - date: 1707223035 version: train-eol - date: 1745485404 version: 12.0.1 - date: 1605785541 version: stein-em - date: 1725623855 version: 11.0.1 - date: 1533810455 version: 2.0.0.0rc1 - date: 1707223786 version: ussuri-eol - date: 1667830428 version: wallaby-em - date: 1589367220 version: 5.0.0 - date: 1523306330 version: 1.0.1 - date: 1509132245 version: 1.0.0.0b1 - date: 1627294740 version: 5.0.1 - date: 1637747121 version: ussuri-em - date: 1710446021 version: 13.0.0.0rc1 - date: 1573091707 version: queens-em - date: 1731430375 version: 2023.1-eom - date: 1519191682 version: 1.0.0.0rc2 - date: 1709665131 version: xena-eom - date: 1618398676 version: 7.0.0 - date: 1582914754 version: rocky-em - date: 1738569126 version: victoria-eol - date: 1709665061 version: wallaby-eom - date: 1616693327 version: 7.0.0.0rc1 - date: 1571229542 version: 4.0.0 - date: 1554898639 version: 3.0.0 - date: 1648641184 version: 9.0.0 - date: 1519817337 version: 1.0.0 - date: 1588867652 version: 5.0.0.0rc2 - date: 1534977143 version: 2.0.0.0rc3 - date: 1746177506 version: 2023.2-eol - date: 1674229219 version: 8.0.1 - date: 1595522563 version: queens-eol - date: 1677769521 version: 11.0.0.0rc1 - date: 1569527517 version: 4.0.0.0rc1 - date: 1535638398 version: 2.0.0 - date: 1643024239 version: 6.0.1 - date: 1622711089 version: train-em - date: 1650393850 version: victoria-em - date: 1664972265 version: 10.0.0 - date: 1695976460 version: 9.0.1 - date: 1742206582 version: 15.0.0.0rc1 - date: 1726146564 version: 14.0.0.0rc1 - date: 1743591187 version: 15.0.0 - date: 1742407226 version: wallaby-eol - date: 1646899511 version: 9.0.0.0rc1 - date: 1611855729 version: stein-eol - date: 1663233290 version: 10.0.0.0rc1 - date: 1612190571 version: 4.0.1 - date: 1660216087 version: 7.0.1 - date: 1565783849 version: 2.0.1 - date: 1553189206 version: 3.0.0.0rc1 - date: 1727866333 version: 14.0.0 - date: 1709665003 version: victoria-eom - date: 1565783840 version: 1.0.2 - date: 1683635386 version: xena-em - date: 1516832288 version: 1.0.0.0b3 - date: 1532651461 version: 2.0.0.0b3 - date: 1622458279 version: 4.0.2 - date: 1559139661 version: 3.0.1 - date: 1712142294 version: 13.0.0 - date: 1595496075 version: 3.1.0 - date: 1601024511 version: 6.0.0.0rc1 - date: 1528403271 version: 2.0.0.0b2 - date: 1714474706 version: zed-eom - date: 1709212058 version: 10.0.1 - date: 1587556055 version: 5.0.0.0rc1 - date: 1633519261 version: 8.0.0 - date: 1582817862 version: 2.0.2 - date: 1742583796 version: yoga-eol - date: 1524158064 version: 2.0.0.0b1 - date: 1512754430 version: 1.0.0.0b2 - date: 1679488272 version: 11.0.0 - date: 1696417819 version: 12.0.0 - date: 1708324566 version: yoga-eom - date: 1694786829 version: 12.0.0.0rc1 - date: 1742581918 version: xena-eol file-contents: releasenotes/notes/Add-ProxyV2-b5537c092737fe41.yaml: features: - 'Added Octavia dashboard support for proxy protocol version 2. ' releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml: fixes: - 'Fixes a namespace collision with the barbican-ui dashboard. ' releasenotes/notes/add-RBAC-43ee180e712294ed.yaml: features: - 'Adds RBAC support to the dashboard panels. ' security: - 'RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC in the dashboard or not, the API RBAC will still be in effect. Enabling RBAC in the dashboard will enforce the policies in the dashboard before the API call is made. ' upgrade: - 'To enable RBAC support in the Octavia dashboard you need to install the generated octavia_dashboard/conf/octavia_policy.yaml file into your horizon openstack_dashboard/conf/ directory and also copy octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py file into your horizon openstack_dashboard/local/local_settings.d/ directory. ' releasenotes/notes/add-allowed-cidrs-ad205b1524da3d2c.yaml: features: - "Add the ability to set allowed_cidrs on the listeners \n" releasenotes/notes/add-az-support-efdd4e7c5dccef21.yaml: features: - 'Added support for availability zones. Can now create a LB in a specific AZ. ' releasenotes/notes/add-ciphers-options-for-listeners-and-pools-8440eaf5a551c44c.yaml: features: - 'Added option to specify TLS ciphers for listeners and pools. The ciphers are represented in OpenSSL syntax. ' releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml: fixes: - 'Draining state was missing from the list of operating states. ' releasenotes/notes/add-insert-headers-a6fd80c837a89536.yaml: features: - 'Adds the ability to set the insertion headers on listeners. ' releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml: features: - 'Adds L7 policy support to the dashboard. ' releasenotes/notes/add-member-backup-32e2ec2553c1ba24.yaml: features: - 'Adds the ability to set member as backup. ' releasenotes/notes/add-sctp-support-a1ea956b7630f47d.yaml: features: - 'Add SCTP support in listener protocol and health-monitor type select boxes. ' releasenotes/notes/add-timeout-options-8988fc477fa46d31.yaml: features: - 'Adds the ability to set the timeout options on listeners. ' releasenotes/notes/add-tls_enabled-support-for-pools-449e39f851535839.yaml: features: - 'Add TLS Enabled switch in the pool control form, allowing to enable/disable TLS communications between a load balancer and its members. ' releasenotes/notes/add-udp-support-acb1a22fb605d3a8.yaml: features: - 'Added UDP protocol support in listeners and pools, added UDP-CONNECT method for health-monitor resources. ' releasenotes/notes/add-x-forwarded-proto-e30b52a3f853ed62.yaml: features: - 'Adds the ability to set the X-Forwarded-Proto insertion header on listeners. ' releasenotes/notes/allows-creation-of-single-resources-9ec5fe87acc7c93c.yaml: fixes: - 'Allows the creation of single resources (i.e Load Balancer) without enforcing the creation of children resources (Listeners, Pools, Health monitors). A switch has been added in the children resource wizards to avoid resource creation. ' releasenotes/notes/auto-refresh-detail-pages-26166d5d9c26edee.yaml: features: - 'Adds the ability to auto refresh detail pages upon action. ' releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml: features: - A new dashboard wizard for Octavia. Allows you to create an Octavia load balancer and related resources such as a listener, pool, pool members, and health monitor. - A view of all the existing Octavia load balancers. - Ability to view details of a Octavia load balancer and drill down to see details for the listener, pool, pool member, and health monitor resources. - Ability to create, update, and delete the Octavia load balancer, listener, pool, pool member, and health monitor resources. - Ability to associate and disassociate floating IP addresses for a load balancer. - Ability to choose from SSL certificates stored by the key-manager service when creating a listener using the TERMINATED_HTTPS protocol. - Ability to choose from existing instances from the compute service or specify external members when adding members to a pool. releasenotes/notes/cascade-delete-e4c9d80a31076540.yaml: features: - 'Allow cascade deletion of load balancer. ' other: - 'This changed the default behavior of load balancer deletion from non-cascade deletion to cascade deletion. ' releasenotes/notes/drop-py-2-7-f3372b5c26171513.yaml: upgrade: - 'Python 2.7 support has been dropped. Last release of octavia-dashboard to support py2.7 is OpenStack Train. The minimum version of Python now supported by octavia-dashboard is Python 3.6. ' releasenotes/notes/edit-default-pool-on-listener-206d8dfeea135360.yaml: features: - 'You can now change the default pool on listeners. ' releasenotes/notes/filter-select-65160dcbe699a96d.yaml: features: - 'Adds a new UI component which works as a standard select control alternative. Options in the component are presented in a table which may be filtered using the select input field. Filtering is done across all table fields. ' upgrade: - 'The new component replaces the standard select for subnet selection in the Load Balancer creation modal wizard.' releasenotes/notes/fix-auth-issue-5226777261765699.yaml: fixes: - 'Fixed an authentication issue with the OpenStack services. The dashboard could not get the list of load balancers. ' releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml: fixes: - Fixed an issue where TERMINATED_HTTPS listener type was greyed out. releasenotes/notes/fix-certificate-list-listener-edit-1d9775d23692c34b.yaml: fixes: - 'Fix a bug that prevented to display the ``default_tls_container_ref`` when editing an HTTP_TERMINATED listener. ' releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml: fixes: - 'Fixed a bug when displaying the member list, some fields were not displayed correctly and new members could not be added. This bug affected only Google Chrome 114 and above. ' releasenotes/notes/fix-flavor-no-flavor-profile-c3e82325f16d5ab8.yaml: fixes: - 'Fixes an issue in the Octavia dashboard where users receive a 403 error when attempting to create a load balancer. This was due to the dashboard attempting to access the flavor profile information which is an administrator only object by default. ' releasenotes/notes/fix-incorrect-region-endpoint-1afc5ebdc6fc4110.yaml: fixes: - 'Fixed a bug when using multi-region deployments, the octavia-dashboard may have used the wrong keystone catalog to get the load-balancer endpoint. ' releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml: fixes: - 'Octavia supports setting the weight of members from 0 to 256, but in Horizon the value 0 was not accepted. This fix allows entering the value 0 as well, which is important for putting a member into DRAINING state. ' releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml: fixes: - 'Fix a bug that prevented the update of non-HTTP and non-HTTPS health monitors. ' releasenotes/notes/flavor-support-0195a486faa16b7f.yaml: features: - 'Add load balancer flavor support. ' issues: - 'The octavia-dashboard requires openstacksdk > 0.24.0 for flavor support. ' releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml: features: - 'The object details pages now use a tabbed navigation for child objects. ' - 'Provisioning and operating status is now available on all object details pages. ' - 'Pools can now change the load balancing algorithm after creation. ' - 'Members now display the subnet_id on the details page. ' - 'Health monitors can now change the expected HTTP codes. ' - 'The session persistence for a pool can now be changed. ' - 'Created at and Updated at times are now visible on the details pages. ' - 'Health monitors can now use alternate IP addresses and ports. ' - 'Listener connection limits can now be updated. ' - 'All objects now allow setting the "Admin State". ' issues: - 'The octavia-dashboard requires openstacksdk >= 0.10.0 to resolve an issue with displaying the health monitor details page. It is expected this will be included in the OpenStack Queens release. ' other: - 'The neutron-lbaas neutron extension is not required to use this dashboard. Load balancers created with neutron-lbaas that have not been migrated to Octavia may not be accessible via this dashboard. Only resources accessible via the Octavia API will be visible in this dashboard. ' prelude: 'The Octavia team is excited to release the 1.0.0 version of the Octavia dashboard. This dashboard uses the Octavia API endpoint via the openstacksdk. This release includes a number of improvements over the old neutron-lbaas-dashboard that worked against the neutron API endpoint. These improvements are listed below in the features section of this release note. ' upgrade: - 'This dashboard can be used alongside the neutron-lbaas-dashboard, but both dashboard panels will use the "Load Balancer" labels. ' releasenotes/notes/list-pools-on-lb-details-page-eb0400bdb2b3650f.yaml: features: - 'Pools attached to a load balancer are now listed on the load balancer details page. ' releasenotes/notes/move-to-python-3.8-86095fce6076fb37.yaml: upgrade: - 'Update Python base version from 3.6 to 3.8. As per Openstack Python runtime versions policy Python 3.8 is the minimum Python version in the Zed release cycle. ' releasenotes/notes/pool-selection-hint-7f282ba1fa014d8c.yaml: features: - 'The pool name is now visible in pool selection drop downs in addition to the pool ID. ' releasenotes/notes/remove-barbicanclient-6b48fcc36afafb62.yaml: fixes: - 'Barbicanclient caused an error when getting secrets. By replacing the code by OpenstackSDK this issue was fixed and the barbicanclient dependency could be dropped from the Octavia Dashboard. ' notes: - files: - - releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml - !!binary | ODc2N2UxMjc3MjNjOTViYWI0MzJhMTM4OTA3YTY5MmYyYzFiNjY2OQ== version: 1.0.2 - files: - - releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml - !!binary | MTk5ZGU0ZGM5NDAxMmZkMGRlYWZkZWYzYmYxZTQyMDcxOTJiZTJmNA== - - releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml - !!binary | MTk5ZGU0ZGM5NDAxMmZkMGRlYWZkZWYzYmYxZTQyMDcxOTJiZTJmNA== version: 1.0.0 - files: - - releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml - !!binary | N2FiMTU1M2M0MmY4OWI4YWZjZDhkMDdmMmFlYjcyOGZjNDU0OGQ0OQ== version: 2.0.1 - files: - - releasenotes/notes/add-RBAC-43ee180e712294ed.yaml - !!binary | ZDkwYzNiZjAzYTJlNzc4M2Y0MDg4NjgwYzJmMmM0MzI4ODcwYjcyNQ== - - releasenotes/notes/add-insert-headers-a6fd80c837a89536.yaml - !!binary | MDUxNzBlYzE3NGViYmNhYTdhMzJkYjBhOTU0MWQ1MDc4ZmEzNTRlYQ== - - releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml - !!binary | NWI3MzI2NDA1YWFiOTdmZThjOTc2ZDFkYzE2ZmY4YzJhNjVmYTc4OA== - - releasenotes/notes/add-member-backup-32e2ec2553c1ba24.yaml - !!binary | ZjExOTRkMmRjMTMxNWZkYTM3MWQ1ZDI3MTE1YWE4ZmQ1ZGU5NGVhNA== - - releasenotes/notes/add-timeout-options-8988fc477fa46d31.yaml - !!binary | ZTk4OTY2Yzc5NWU4NmRhNWNmYTBmNGMyNjI3NjI0MWI0ZTM5ODEzMw== - - releasenotes/notes/auto-refresh-detail-pages-26166d5d9c26edee.yaml - !!binary | YmIwY2I4NjQ1MTI1YjRhY2Q1MjRlZDY5YjBmYWZjZmMzMmQ5NGQ3NQ== - - releasenotes/notes/edit-default-pool-on-listener-206d8dfeea135360.yaml - !!binary | ZTliMzk4OGE5ZDQ5Zjc2Y2VmMGUxNDVjOWZlZWVmMTFmNjI3MzIwOA== - - releasenotes/notes/list-pools-on-lb-details-page-eb0400bdb2b3650f.yaml - !!binary | OTcxMTc2MGIzMzdhOGY4ODdjMTlhZDNmZmIwOWM0ZWFiZTlmZjkwYQ== - - releasenotes/notes/pool-selection-hint-7f282ba1fa014d8c.yaml - !!binary | MmY2ZTJhMzg2YzRjNDk5YTI5OWQ3ZTZlYWYwNzc4OTA0YTVlMmIxNw== version: 2.0.0 - files: - - releasenotes/notes/fix-flavor-no-flavor-profile-c3e82325f16d5ab8.yaml - !!binary | NzRhMDdjOWMwMjdlY2ZhOTViMjQzMWYyYTgwNTU2ZjRjMGU5ZjU0NA== version: 3.0.1 - files: - - releasenotes/notes/add-x-forwarded-proto-e30b52a3f853ed62.yaml - !!binary | OTBhYTBmNDFmNGU4NDYyYmVkMGI4ZWE4M2NmZWJlMzcxZjA2ODQyNA== - - releasenotes/notes/cascade-delete-e4c9d80a31076540.yaml - !!binary | NzJmOGZmMTZlYjIwNTkyY2ZhOWJkMzMwMGIwMzJjYTZkNjY0ZjcyZA== - - releasenotes/notes/filter-select-65160dcbe699a96d.yaml - !!binary | MzVmNmY5MGQwY2IyOGM0NDQzODBkNDc3Zjk1NThiZDRiZWYxMWZmOA== - - releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml - !!binary | OWZjNGIwMzVjZjM0NDQ1YzVhMzA3OWI0ZDE4M2I5YmNlNWE4Yzc0MQ== - - releasenotes/notes/flavor-support-0195a486faa16b7f.yaml - !!binary | MzhlODM1Y2VlYTM5ODQ5YTA3ODlmYzRmNDljZmQ4YWFjZjc1NTI3Yg== version: 3.0.0 - files: - - releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml - !!binary | MjM1ODA4NGE1MzI5YTRhMjRlM2NjMjNhYjE2ZDY2MzdlN2MwNzc2OQ== - - releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml - !!binary | MTJjYTIzYTU1MjI1YjY2NzY3ZjM0M2E2MzU1OWMwZTJhODc1MzIxNg== - - releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml - !!binary | MmNjZTk4YjIwODBjMTU2Y2E5MjlhYTFhYzJhMjA0NDllZjYxOTI0Yw== - - releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml - !!binary | N2IwODI5OWQwZjkwNzliZWQ3OTJlNzFkNDU5MzJlYzJmZThiZmQyYw== version: 4.0.2-5 - files: - - releasenotes/notes/add-udp-support-acb1a22fb605d3a8.yaml - !!binary | MGUxOTBmOTJkNzRjYmIyNjc3YTM5MGEwMGI0ODI2YjY4MzViMWU5Mw== - - releasenotes/notes/fix-flavor-no-flavor-profile-c3e82325f16d5ab8.yaml - !!binary | YTI3ZWQ2OWYxZTk3Mjk0YTQ2NzJiM2Y4MTU0OTViYWFlZGJmMDFlZQ== version: 4.0.0 - files: - - releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml - !!binary | ODQzYWM1MTU3OTViNzBkMmEwNTU1NTY2MDJiZTY5ZjI0ZmIxNjRjMA== - - releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml - !!binary | NjM5ODQyMTgxZjE0M2YwMjY1YWM2YzdmNDcwZmRiYmYzMzY1ZWRkNg== - - releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml - !!binary | ZDExZDBmZTRlNjM2OGQ0YWNkYTMwMzU3OGQ4ZTdlYmFhYWI4OWNlYg== - - releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml - !!binary | NThjYmY5MzQxMmI4ZWI2NzM0MGY1ZTcxZTlkYTQ1Y2JlZTM3OGEzOA== version: 5.0.2-4 - files: - - releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml - !!binary | ZmQ3M2IyMTMwMjY2MTdhMjk0OWNlYmNjODM0Yjg0MjQ2ZGQ1NDBhMw== version: 5.0.2 - files: - - releasenotes/notes/add-az-support-efdd4e7c5dccef21.yaml - !!binary | NzYxNDA4ZTNiODM3MTJiYWE3Y2EyODFhYjE2ODUyNTVkNzBiMTNjMw== - - releasenotes/notes/drop-py-2-7-f3372b5c26171513.yaml - !!binary | MmZkN2Q2ZWRlMjIzZmNmZjYyNmNlYTBmOWZmMjA5MWY3Mjk4NmY3NQ== version: 5.0.0 - files: - - releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml - !!binary | MjhlYTc4MDMxZGQ2YTFlYmJlYWZkMDE1NTZiNmVmOGI5YzU0N2M5Nw== - - releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml - !!binary | NGY3OTQyY2UzMjcyMTAwOWI4Njc1Yjg5OTRjZDBlY2ZmMTRhZmI5Yw== - - releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml - !!binary | OTZjZGRlMjZlN2UyNTMwNTgzOWYwOTUxNmZkNjdmYTcwN2U1YmU1NA== - - releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml - !!binary | YmZhYzAxNDVlNmRkODZhM2I0YTM1MzRjNWI5ODc4NmEwMjdhNTQ2Mg== version: 6.0.1-6 - files: - - releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml - !!binary | M2FlZjFmNzQyMzA1MmExNjFkOWNjNTAwZThmZWY3ODlmYzI2YmMyOA== version: 6.0.1 - files: - - releasenotes/notes/Add-ProxyV2-b5537c092737fe41.yaml - !!binary | NmE4Zjg4MDdlYjdmNzU5NjBmMTU2NTEwNTQ2YTIwZTA3YWVkY2NlMw== version: 6.0.0 - files: - - releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml - !!binary | MmJjYTBlZDA3MmJmMTY4MzMwMDdhY2M0NWQzYzFjMzU5ZTg5NGIwMw== - - releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml - !!binary | MDU3NDA0YTEzNGUzMzk4ZGI3ZjdkMjQ3Yjc2NDM0YWZjNmJlMWZhNg== version: 7.0.1-4 - files: - - releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml - !!binary | YjRjNzZiOTY4NjhkZDIyZDVkMWYzMDZhYzAxMTI5ZWI4ODJlMmQ3NA== - - releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml - !!binary | NzZjZjkyMGViNDc2ZDBhODMxM2UyMmExMTJjMTk0MjllNzdjN2QxNA== - - releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml - !!binary | ZmMyNGI4NDk1ZjlhYmNkNTlkNjU0OGUzNjk5Mzc0MGMwODM0NmRkNw== version: 7.0.1 - files: - - releasenotes/notes/add-allowed-cidrs-ad205b1524da3d2c.yaml - !!binary | ZjQ0MTdjYjk3ZGFiMmNkYzRjYWRhYjQ3ZjA2NjYwY2U1NWM4NjA5Yw== - - releasenotes/notes/add-ciphers-options-for-listeners-and-pools-8440eaf5a551c44c.yaml - !!binary | ZGFhZTZkMWZjZDQzMmQwODg1ODgwNzA5ZGNiZmQwNjE0MDcxNTY0NA== - - releasenotes/notes/add-sctp-support-a1ea956b7630f47d.yaml - !!binary | MjYwZWM3NjEwY2E2MDA2YmQyYTU3ZGJiNzcxZjY2ODNhMTBjNjAwNA== - - releasenotes/notes/add-tls_enabled-support-for-pools-449e39f851535839.yaml - !!binary | NDAwYzExOTRlMDllNzBjMGIyOGUyNGZiZGMyNzQyNjYyNmYzYmQzYQ== - - releasenotes/notes/allows-creation-of-single-resources-9ec5fe87acc7c93c.yaml - !!binary | NmNlMDM3NTE4YTc3MDQ4NjYzMWMxMzJkODVjYWE5MDA2YzE3MjE5NQ== version: 7.0.0 - files: - - releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml - !!binary | M2VhZTYyOTI1ZTRhYWRmYjcwYzdmZjJkNGE3ZDA5NzBhNmRmMTkwNg== - - releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml - !!binary | ZDVmZjdmZWQyMjk2NDNhOTM3YzAxMjE5NDQ3ZmVlODUxYTFmMmFmYQ== version: 8.0.1-4 - files: - - releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml - !!binary | Nzc1Y2YxMzk5ZWY5YTg4ZjE5OWNlYmJjMDZjY2FkNTYxMWY1ZGFlNg== - - releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml - !!binary | NzI5OGMxYTQ2ZjhiMWJmN2U1ZGVjODc0NDgyNzA0ZmM4M2NhZjFhZQ== version: 8.0.1 - files: - - releasenotes/notes/Fix-namespace-collision-with-barbican-ui-267f4ba074729ea6.yaml - !!binary | N2UzOTAzMTJlYWYzY2JiZjg5ZDQ2YjA1ZGQyMGI1Mjk2ZDYxNjE2ZA== version: 8.0.0 - files: - - releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml - !!binary | Yjc3ODVkMjA2ZTUwNjM0YjlkNmY3MmIxMDQzM2IwNjU0NDcwZWVmNg== - - releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml - !!binary | NzQxMjQwMjg5NDhjY2VmMzRmNDc3ODU2Y2NiZTIyNGYzMjY5MjZkOQ== version: 9.0.1 - files: - - releasenotes/notes/add-draining-operating-status-48f59a204371ff0d.yaml - !!binary | NmZkYWI0YTZjMDgwM2Y5NmFkZDJkMWJkYzUyZTIwMTA3OTBjMWY2Ng== - - releasenotes/notes/fix-member-weight-value-range-9310678f967c771a.yaml - !!binary | YjFhODZiYjZmZjNmYTc4NGI3MzM2NDE1OTRlZWE4NmMyYmIwMDhkOQ== version: 9.0.0 - files: - - releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml - !!binary | YmQxYTMyOWI0NmQxOGJhYTQyYTliYTQ4ZDgwMzE1NDlhOTdhN2JmMg== version: 10.0.1 - files: - - releasenotes/notes/fix-updating-non-http-hm-114180139961e441.yaml - !!binary | YThkYzk0ZmRiZDRiNDZiMTZkNzdhMmNkNjM5MzFlZTQwNzhlNDhmOQ== - - releasenotes/notes/move-to-python-3.8-86095fce6076fb37.yaml - !!binary | NTM3ODY1ZDJmYWE2ZjZkMWNjNWY1NjZlZmJjNzNlZDE5ODcwZTQxMA== version: 10.0.0 - files: - - releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml - !!binary | NmY5OTBlMDllNzY4MWJkNjNiNzg0ZGFkNDBlOGRlZjc5NGZjZWI3MQ== - - releasenotes/notes/remove-barbicanclient-6b48fcc36afafb62.yaml - !!binary | ZmE4ZmJjZmNmODNhMGQzZWE3YjM0MzFkODM4MWQ2YmQxM2JmY2ExYQ== version: 2023.1-eom - files: - - releasenotes/notes/fix-incorrect-region-endpoint-1afc5ebdc6fc4110.yaml - !!binary | ZDFjYmMwNzYxNGU2MmI4Mzc4NDU3MTRiYjQ5ZmYyOGRhYjQ2OTA4YQ== version: 2023.2-eol - files: - - releasenotes/notes/fix-chrome-member-dialog-154981a7794d5fb4.yaml - !!binary | OWNjNGJmYWM1OGI5MDFiMzJjNThkMzZmZmFiMzU4NTY0NWY3OWJlNQ== - - releasenotes/notes/remove-barbicanclient-6b48fcc36afafb62.yaml - !!binary | NmZiNjg3MWVlMGZlMjJiNGU2NjFlZGY4ZWRjNWE5MzEyOWFmZmE5OA== version: 12.0.0 - files: - - releasenotes/notes/fix-incorrect-region-endpoint-1afc5ebdc6fc4110.yaml - !!binary | ZGYxMmQ0ZjA4MGRmMTMzMGMyNGFiY2U3ZTVjM2IxNGM0NjQxYjNjZQ== version: 13.0.0-3 - files: - - releasenotes/notes/fix-auth-issue-5226777261765699.yaml - !!binary | OTJkNzJmMTIyMGVmYmU2ZjIxMTgxYmVmYmRiM2RlMGQyODY3MGFmMg== version: 13.0.0 - files: - - releasenotes/notes/fix-incorrect-region-endpoint-1afc5ebdc6fc4110.yaml - !!binary | MGY1OWIwZDE2NGVlMGJmZTEwNjE4OWEyNzA0YzZiZmQ1NjI2ZGY3Yg== version: 14.0.0 - files: - - releasenotes/notes/fix-certificate-list-listener-edit-1d9775d23692c34b.yaml - !!binary | ZGQzNDU3MDdjMWI3Yjg3N2Y2MjMzMjJjMDBlZDc5NjllZGMxNTE4OQ== version: 15.0.0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/releasenotes/source/0000775000175100017510000000000015033037476021203 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/2023.1.rst0000664000175100017510000000021015033037474022451 0ustar00mylesmyles=========================== 2023.1 Series Release Notes =========================== .. release-notes:: :branch: unmaintained/2023.1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/2023.2.rst0000664000175100017510000000020215033037474022453 0ustar00mylesmyles=========================== 2023.2 Series Release Notes =========================== .. release-notes:: :branch: stable/2023.2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/2024.1.rst0000664000175100017510000000020215033037474022453 0ustar00mylesmyles=========================== 2024.1 Series Release Notes =========================== .. release-notes:: :branch: stable/2024.1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/2024.2.rst0000664000175100017510000000020215033037474022454 0ustar00mylesmyles=========================== 2024.2 Series Release Notes =========================== .. release-notes:: :branch: stable/2024.2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/2025.1.rst0000664000175100017510000000020215033037474022454 0ustar00mylesmyles=========================== 2025.1 Series Release Notes =========================== .. release-notes:: :branch: stable/2025.1 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/releasenotes/source/_static/0000775000175100017510000000000015033037476022631 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/_static/.placeholder0000664000175100017510000000000015033037474025100 0ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/releasenotes/source/_templates/0000775000175100017510000000000015033037476023340 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/_templates/.placeholder0000664000175100017510000000000015033037474025607 0ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/conf.py0000664000175100017510000001173315033037474022505 0ustar00mylesmyles# -*- coding: utf-8 -*- # 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. # # octavia-dashboard documentation build configuration file, created by # sphinx-quickstart on Wed Oct 18 09:02:08 2017. # # 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. # # import os # import sys # 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 openstackdocs_repo_name = 'openstack/octavia-dashboard' openstackdocs_use_storyboard = True # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. copyright = '2017, Octavia Developers' author = 'Octavia Developers' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. # language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'native' # If true, `todo` and `todoList` produce output, else they produce nothing. # todo_include_todos = 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 = 'openstackdocs' # 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 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'] # If false, no module index is generated. html_domain_indices = False # If false, no index is generated. html_use_index = False # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. htmlhelp_basename = 'OctaviaDashboardReleaseNotesdoc' # -- Options for LaTeX output --------------------------------------------- # 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 = [ (master_doc, 'octavia-dashboard.tex', 'octavia-dashboard Documentation', 'Octavia Developers', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'octavia-dashboard', 'octavia-dashboard Documentation', [author], 1) ] # -- 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 = [ (master_doc, 'octavia-dashboard', 'octavia-dashboard Documentation', author, 'octavia-dashboard', 'One line description of project.', 'Miscellaneous'), ] # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/index.rst0000664000175100017510000000154215033037474023044 0ustar00mylesmyles.. 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. =============================== Octavia Dashboard Release Notes =============================== .. toctree:: :maxdepth: 1 unreleased 2025.1 2024.2 2024.1 2023.2 2023.1 zed yoga xena wallaby victoria ussuri train stein rocky queens ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4611008 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/0000775000175100017510000000000015033037476022442 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.460101 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/de/0000775000175100017510000000000015033037476023032 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/de/LC_MESSAGES/0000775000175100017510000000000015033037476024617 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/de/LC_MESSAGES/releasenotes.po0000664000175100017510000000552115033037474027651 0ustar00mylesmyles# Robert Simai , 2018. #zanata # Andreas Jaeger , 2019. #zanata # Robert Simai , 2019. #zanata # Andreas Jaeger , 2020. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-20 15:28+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2020-10-05 06:34+0000\n" "Last-Translator: Andreas Jaeger \n" "Language-Team: German\n" "Language: de\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "1.0.0" msgstr "1.0.0" msgid "1.0.2" msgstr "1.0.2" msgid "2.0.0" msgstr "2.0.0" msgid "2.0.1" msgstr "2.0.1" msgid "3.0.0" msgstr "3.0.0" msgid "3.0.1" msgstr "3.0.1" msgid "4.0.0" msgstr "4.0.0" msgid "5.0.0" msgstr "5.0.0" msgid "A view of all the existing Octavia load balancers." msgstr "Ansicht aller vorhandenen Octavia Loadbalancer" msgid "Adds L7 policy support to the dashboard." msgstr "Fügt L7 Richtlinienunterstützung zum Dashboard hinzu." msgid "Adds RBAC support to the dashboard panels." msgstr "Fügt RBAC-Unterstützung zu den Dashboard-Paneelen hinzu." msgid "All objects now allow setting the \"Admin State\"." msgstr "Alle Objekte erlauben jetzt das Setzen des \"Admin Status\"." msgid "Bug Fixes" msgstr "Fehlerkorrekturen" msgid "Current Series Release Notes" msgstr "Aktuelle Serie Releasenotes" msgid "Known Issues" msgstr "Bekannte Probleme" msgid "Listener connection limits can now be updated." msgstr "Listener-Verbindungen können jetzt aktualisiert werden." msgid "New Features" msgstr "Neue Funktionen" msgid "Octavia Dashboard Release Notes" msgstr "Octavia Dashboard Releasenotes" msgid "Other Notes" msgstr "Andere Notizen" msgid "Prelude" msgstr "Einleitung" msgid "" "Python 2.7 support has been dropped. Last release of octavia-dashboard to " "support py2.7 is OpenStack Train. The minimum version of Python now " "supported by octavia-dashboard is Python 3.6." msgstr "" "Python 2.7 Unterstützung wurde beendet. Der letzte Release von octavia-" "dashboard welcher Python 2.7 unterstützt ist OpenStack Train. Die minimal " "Python Version welche von octavia-dashboard unterstützt wird, ist Python 3.6." msgid "Queens Series Release Notes" msgstr "Queens Serie Releasenotes" msgid "Rocky Series Release Notes" msgstr "Rocky Serie Releasenotes" msgid "Security Issues" msgstr "Sicherheitsrelevante Probleme" msgid "Stein Series Release Notes" msgstr "Stein Serie Releasenotes" msgid "Train Series Release Notes" msgstr "Train Serie Releasenotes" msgid "Upgrade Notes" msgstr "Aktualisierungsnotizen" msgid "Ussuri Series Release Notes" msgstr "Ussuri Serie Releasenotes" msgid "Victoria Series Release Notes" msgstr "Victoria Serie Releasenotes" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.460101 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/en_GB/0000775000175100017510000000000015033037476023414 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/en_GB/LC_MESSAGES/0000775000175100017510000000000015033037476025201 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po0000664000175100017510000004267215033037474030243 0ustar00mylesmyles# Andi Chandler , 2017. #zanata # Andi Chandler , 2018. #zanata # Andi Chandler , 2019. #zanata # Andi Chandler , 2020. #zanata # Andi Chandler , 2022. #zanata # Andi Chandler , 2023. #zanata # Andi Chandler , 2024. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-03-19 12:02+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2024-04-18 12:31+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "1.0.0" msgstr "1.0.0" msgid "1.0.2" msgstr "1.0.2" msgid "10.0.0" msgstr "10.0.0" msgid "10.0.1" msgstr "10.0.1" msgid "11.0.0-4" msgstr "11.0.0-4" msgid "12.0.0" msgstr "12.0.0" msgid "13.0.0.0rc1" msgstr "13.0.0.0rc1" msgid "2.0.0" msgstr "2.0.0" msgid "2.0.1" msgstr "2.0.1" msgid "2023.1 Series Release Notes" msgstr "2023.1 Series Release Notes" msgid "2023.2 Series Release Notes" msgstr "2023.2 Series Release Notes" msgid "2024.1 Series Release Notes" msgstr "2024.1 Series Release Notes" msgid "3.0.0" msgstr "3.0.0" msgid "3.0.1" msgstr "3.0.1" msgid "4.0.0" msgstr "4.0.0" msgid "4.0.2-5" msgstr "4.0.2-5" msgid "5.0.0" msgstr "5.0.0" msgid "5.0.2" msgstr "5.0.2" msgid "5.0.2-4" msgstr "5.0.2-4" msgid "6.0.0" msgstr "6.0.0" msgid "6.0.1" msgstr "6.0.1" msgid "6.0.1-6" msgstr "6.0.1-6" msgid "7.0.0" msgstr "7.0.0" msgid "7.0.1" msgstr "7.0.1" msgid "7.0.1-4" msgstr "7.0.1-4" msgid "8.0.0" msgstr "8.0.0" msgid "8.0.1" msgstr "8.0.1" msgid "8.0.1-4" msgstr "8.0.1-4" msgid "9.0.0" msgstr "9.0.0" msgid "9.0.1" msgstr "9.0.1" msgid "" "A new dashboard wizard for Octavia. Allows you to create an Octavia load " "balancer and related resources such as a listener, pool, pool members, and " "health monitor." msgstr "" "A new dashboard wizard for Octavia. Allows you to create an Octavia load " "balancer and related resources such as a listener, pool, pool members, and " "health monitor." msgid "A view of all the existing Octavia load balancers." msgstr "A view of all the existing Octavia load balancers." msgid "" "Ability to associate and disassociate floating IP addresses for a load " "balancer." msgstr "" "Ability to associate and disassociate Floating IP addresses for a load " "balancer." msgid "" "Ability to choose from SSL certificates stored by the key-manager service " "when creating a listener using the TERMINATED_HTTPS protocol." msgstr "" "Ability to choose from SSL certificates stored by the key-manager service " "when creating a listener using the TERMINATED_HTTPS protocol." msgid "" "Ability to choose from existing instances from the compute service or " "specify external members when adding members to a pool." msgstr "" "Ability to choose from existing instances from the compute service or " "specify external members when adding members to a pool." msgid "" "Ability to create, update, and delete the Octavia load balancer, listener, " "pool, pool member, and health monitor resources." msgstr "" "Ability to create, update, and delete the Octavia load balancer, listener, " "pool, pool member, and health monitor resources." msgid "" "Ability to view details of a Octavia load balancer and drill down to see " "details for the listener, pool, pool member, and health monitor resources." msgstr "" "Ability to view details of a Octavia load balancer and drill down to see " "details for the listener, pool, pool member, and health monitor resources." msgid "" "Add SCTP support in listener protocol and health-monitor type select boxes." msgstr "" "Add SCTP support in listener protocol and health-monitor type select boxes." msgid "" "Add TLS Enabled switch in the pool control form, allowing to enable/disable " "TLS communications between a load balancer and its members." msgstr "" "Add TLS Enabled switch in the pool control form, allowing to enable/disable " "TLS communications between a load balancer and its members." msgid "Add load balancer flavor support." msgstr "Add load balancer flavour support." msgid "Add the ability to set allowed_cidrs on the listeners" msgstr "Add the ability to set allowed_cidrs on the listeners" msgid "Added Octavia dashboard support for proxy protocol version 2." msgstr "Added Octavia dashboard support for proxy protocol version 2." msgid "" "Added UDP protocol support in listeners and pools, added UDP-CONNECT method " "for health-monitor resources." msgstr "" "Added UDP protocol support in listeners and pools, added UDP-CONNECT method " "for health-monitor resources." msgid "" "Added option to specify TLS ciphers for listeners and pools. The ciphers are " "represented in OpenSSL syntax." msgstr "" "Added option to specify TLS ciphers for listeners and pools. The ciphers are " "represented in OpenSSL syntax." msgid "" "Added support for availability zones. Can now create a LB in a specific AZ." msgstr "" "Added support for availability zones. Can now create a LB in a specific AZ." msgid "Adds L7 policy support to the dashboard." msgstr "Adds L7 policy support to the dashboard." msgid "Adds RBAC support to the dashboard panels." msgstr "Adds RBAC support to the dashboard panels." msgid "" "Adds a new UI component which works as a standard select control " "alternative. Options in the component are presented in a table which may be " "filtered using the select input field. Filtering is done across all table " "fields." msgstr "" "Adds a new UI component which works as a standard select control " "alternative. Options in the component are presented in a table which may be " "filtered using the select input field. Filtering is done across all table " "fields." msgid "Adds the ability to auto refresh detail pages upon action." msgstr "Adds the ability to auto refresh detail pages upon action." msgid "Adds the ability to set member as backup." msgstr "Adds the ability to set member as backup." msgid "" "Adds the ability to set the X-Forwarded-Proto insertion header on listeners." msgstr "" "Adds the ability to set the X-Forwarded-Proto insertion header on listeners." msgid "Adds the ability to set the insertion headers on listeners." msgstr "Adds the ability to set the insertion headers on listeners." msgid "Adds the ability to set the timeout options on listeners." msgstr "Adds the ability to set the timeout options on listeners." msgid "All objects now allow setting the \"Admin State\"." msgstr "All objects now allow setting the \"Admin State\"." msgid "Allow cascade deletion of load balancer." msgstr "Allow cascade deletion of load balancer." msgid "" "Allows the creation of single resources (i.e Load Balancer) without " "enforcing the creation of children resources (Listeners, Pools, Health " "monitors). A switch has been added in the children resource wizards to avoid " "resource creation." msgstr "" "Allows the creation of single resources (i.e Load Balancer) without " "enforcing the creation of children resources (Listeners, Pools, Health " "monitors). A switch has been added in the children's resource wizards to " "avoid resource creation." msgid "" "Barbicanclient caused an error when getting secrets. By replacing the code " "by OpenstackSDK this issue was fixed and the barbicanclient dependency could " "be dropped from the Octavia Dashboard." msgstr "" "Barbicanclient caused an error when getting secrets. By replacing the code " "by OpenstackSDK this issue was fixed and the barbicanclient dependency could " "be dropped from the Octavia Dashboard." msgid "Bug Fixes" msgstr "Bug Fixes" msgid "Created at and Updated at times are now visible on the details pages." msgstr "Created at and Updated at times are now visible on the details pages." msgid "Current Series Release Notes" msgstr "Current Series Release Notes" msgid "Draining state was missing from the list of operating states." msgstr "Draining state was missing from the list of operating states." msgid "" "Fix a bug that prevented the update of non-HTTP and non-HTTPS health " "monitors." msgstr "" "Fix a bug that prevented the update of non-HTTP and non-HTTPS health " "monitors." msgid "" "Fixed a bug when displaying the member list, some fields were not displayed " "correctly and new members could not be added. This bug affected only Google " "Chrome 114 and above." msgstr "" "Fixed a bug when displaying the member list, some fields were not displayed " "correctly and new members could not be added. This bug affected only Google " "Chrome 114 and above." msgid "" "Fixed an authentication issue with the OpenStack services. The dashboard " "could not get the list of load balancers." msgstr "" "Fixed an authentication issue with the OpenStack services. The dashboard " "could not get the list of load balancers." msgid "Fixed an issue where TERMINATED_HTTPS listener type was greyed out." msgstr "Fixed an issue where TERMINATED_HTTPS listener type was greyed out." msgid "Fixes a namespace collision with the barbican-ui dashboard." msgstr "Fixes a namespace collision with the barbican-ui dashboard." msgid "" "Fixes an issue in the Octavia dashboard where users receive a 403 error when " "attempting to create a load balancer. This was due to the dashboard " "attempting to access the flavor profile information which is an " "administrator only object by default." msgstr "" "Fixes an issue in the Octavia dashboard where users receive a 403 error when " "attempting to create a load balancer. This was due to the dashboard " "attempting to access the flavour profile information which is an " "administrator only object by default." msgid "Health monitors can now change the expected HTTP codes." msgstr "Health monitors can now change the expected HTTP codes." msgid "Health monitors can now use alternate IP addresses and ports." msgstr "Health monitors can now use alternate IP addresses and ports." msgid "Known Issues" msgstr "Known Issues" msgid "Listener connection limits can now be updated." msgstr "Listener connection limits can now be updated." msgid "Members now display the subnet_id on the details page." msgstr "Members now display the subnet_id on the details page." msgid "New Features" msgstr "New Features" msgid "Octavia Dashboard Release Notes" msgstr "Octavia Dashboard Release Notes" msgid "" "Octavia supports setting the weight of members from 0 to 256, but in Horizon " "the value 0 was not accepted. This fix allows entering the value 0 as well, " "which is important for putting a member into DRAINING state." msgstr "" "Octavia supports setting the weight of members from 0 to 256, but in Horizon " "the value 0 was not accepted. This fix allows entering the value 0 as well, " "which is important for putting a member into the DRAINING state." msgid "Other Notes" msgstr "Other Notes" msgid "" "Pools attached to a load balancer are now listed on the load balancer " "details page." msgstr "" "Pools attached to a Load Balancer are now listed on the Load Balancer " "details page." msgid "Pools can now change the load balancing algorithm after creation." msgstr "Pools can now change the load balancing algorithm after creation." msgid "Prelude" msgstr "Prelude" msgid "" "Provisioning and operating status is now available on all object details " "pages." msgstr "" "Provisioning and operating status is now available on all object details " "pages." msgid "" "Python 2.7 support has been dropped. Last release of octavia-dashboard to " "support py2.7 is OpenStack Train. The minimum version of Python now " "supported by octavia-dashboard is Python 3.6." msgstr "" "Python 2.7 support has been dropped. Last release of octavia-dashboard to " "support py2.7 is OpenStack Train. The minimum version of Python now " "supported by octavia-dashboard is Python 3.6." msgid "Queens Series Release Notes" msgstr "Queens Series Release Notes" msgid "" "RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC " "in the dashboard or not, the API RBAC will still be in effect. Enabling RBAC " "in the dashboard will enforce the policies in the dashboard before the API " "call is made." msgstr "" "RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC " "in the dashboard or not, the API RBAC will still be in effect. Enabling RBAC " "in the dashboard will enforce the policies in the dashboard before the API " "call is made." msgid "Rocky Series Release Notes" msgstr "Rocky Series Release Notes" msgid "Security Issues" msgstr "Security Issues" msgid "Stein Series Release Notes" msgstr "Stein Series Release Notes" msgid "" "The Octavia team is excited to release the 1.0.0 version of the Octavia " "dashboard. This dashboard uses the Octavia API endpoint via the " "openstacksdk. This release includes a number of improvements over the old " "neutron-lbaas-dashboard that worked against the neutron API endpoint. These " "improvements are listed below in the features section of this release note." msgstr "" "The Octavia team is excited to release the 1.0.0 version of the Octavia " "dashboard. This dashboard uses the Octavia API endpoint via the " "OpenStackSDK. This release includes a number of improvements over the old " "neutron-lbaas-dashboard that worked against the neutron API endpoint. These " "improvements are listed below in the features section of this release note." msgid "" "The neutron-lbaas neutron extension is not required to use this dashboard. " "Load balancers created with neutron-lbaas that have not been migrated to " "Octavia may not be accessible via this dashboard. Only resources accessible " "via the Octavia API will be visible in this dashboard." msgstr "" "The neutron-lbaas Neutron extension is not required to use this dashboard. " "Load balancers created with neutron-lbaas that have not been migrated to " "Octavia may not be accessible via this dashboard. Only resources accessible " "via the Octavia API will be visible in this dashboard." msgid "" "The new component replaces the standard select for subnet selection in the " "Load Balancer creation modal wizard." msgstr "" "The new component replaces the standard select for subnet selection in the " "Load Balancer creation modal wizard." msgid "The object details pages now use a tabbed navigation for child objects." msgstr "" "The object details pages now use a tabbed navigation for child objects." msgid "" "The octavia-dashboard requires openstacksdk > 0.24.0 for flavor support." msgstr "" "The octavia-dashboard requires openstacksdk > 0.24.0 for flavour support." msgid "" "The octavia-dashboard requires openstacksdk >= 0.10.0 to resolve an issue " "with displaying the health monitor details page. It is expected this will be " "included in the OpenStack Queens release." msgstr "" "The Octavia-Dashboard requires openstacksdk >= 0.10.0 to resolve an issue " "with displaying the health monitor details page. It is expected this will be " "included in the OpenStack Queens release." msgid "" "The pool name is now visible in pool selection drop downs in addition to the " "pool ID." msgstr "" "The pool name is now visible in pool selection drop downs in addition to the " "pool ID." msgid "The session persistence for a pool can now be changed." msgstr "The session persistence for a pool can now be changed." msgid "" "This changed the default behavior of load balancer deletion from non-cascade " "deletion to cascade deletion." msgstr "" "This changed the default behaviour of load balancer deletion from non-" "cascade deletion to cascade deletion." msgid "" "This dashboard can be used alongside the neutron-lbaas-dashboard, but both " "dashboard panels will use the \"Load Balancer\" labels." msgstr "" "This dashboard can be used alongside the neutron-lbaas-dashboard, but both " "dashboard panels will use the \"Load Balancer\" labels." msgid "" "To enable RBAC support in the Octavia dashboard you need to install the " "generated octavia_dashboard/conf/octavia_policy.yaml file into your horizon " "openstack_dashboard/conf/ directory and also copy octavia_dashboard/" "local_settings.d/_1499_load_balancer_settings.py file into your horizon " "openstack_dashboard/local/local_settings.d/ directory." msgstr "" "To enable RBAC support in the Octavia dashboard you need to install the " "generated octavia_dashboard/conf/octavia_policy.yaml file into your horizon " "openstack_dashboard/conf/ directory and also copy octavia_dashboard/" "local_settings.d/_1499_load_balancer_settings.py file into your horizon " "openstack_dashboard/local/local_settings.d/ directory." msgid "Train Series Release Notes" msgstr "Train Series Release Notes" msgid "" "Update Python base version from 3.6 to 3.8. As per Openstack Python runtime " "versions policy Python 3.8 is the minimum Python version in the Zed release " "cycle." msgstr "" "Update Python base version from 3.6 to 3.8. As per the OpenStack Python " "runtime versions policy Python 3.8 is the minimum Python version in the Zed " "release cycle." msgid "Upgrade Notes" msgstr "Upgrade Notes" msgid "Ussuri Series Release Notes" msgstr "Ussuri Series Release Notes" msgid "Victoria Series Release Notes" msgstr "Victoria Series Release Notes" msgid "Wallaby Series Release Notes" msgstr "Wallaby Series Release Notes" msgid "Xena Series Release Notes" msgstr "Xena Series Release Notes" msgid "Yoga Series Release Notes" msgstr "Yoga Series Release Notes" msgid "You can now change the default pool on listeners." msgstr "You can now change the default pool on listeners." msgid "Zed Series Release Notes" msgstr "Zed Series Release Notes" ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.460101 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/id/0000775000175100017510000000000015033037476023036 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/id/LC_MESSAGES/0000775000175100017510000000000015033037476024623 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/id/LC_MESSAGES/releasenotes.po0000664000175100017510000002734315033037474027663 0ustar00mylesmyles# suhartono , 2018. #zanata # suhartono , 2019. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-10-23 02:50+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2019-09-03 04:53+0000\n" "Last-Translator: suhartono \n" "Language-Team: Indonesian\n" "Language: id\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "1.0.0" msgstr "1.0.0" msgid "1.0.2" msgstr "1.0.2" msgid "2.0.0" msgstr "2.0.0" msgid "2.0.1" msgstr "2.0.1" msgid "3.0.0" msgstr "3.0.0" msgid "3.0.1" msgstr "3.0.1" msgid "" "A new dashboard wizard for Octavia. Allows you to create an Octavia load " "balancer and related resources such as a listener, pool, pool members, and " "health monitor." msgstr "" "Wizard dashboard baru untuk Octavia. Memungkinkan Anda untuk membuat load " "balancing Octavia dan sumber daya terkait seperti listener, pool, pool " "members, dan health monitor." msgid "A view of all the existing Octavia load balancers." msgstr "Tampilan dari semua load balancing Octavia yang ada." msgid "" "Ability to associate and disassociate floating IP addresses for a load " "balancer." msgstr "" "Kemampuan untuk mengasosiasikan dan memisahkan alamat IP mengambang untuk " "load balancer." msgid "" "Ability to choose from SSL certificates stored by the key-manager service " "when creating a listener using the TERMINATED_HTTPS protocol." msgstr "" "Kemampuan untuk memilih dari sertifikat SSL yang disimpan oleh layanan key-" "manager saat membuat listener menggunakan protokol TERMINATED_HTTPS." msgid "" "Ability to choose from existing instances from the compute service or " "specify external members when adding members to a pool." msgstr "" "Kemampuan untuk memilih dari instance yang ada dari layanan komputasi atau " "menentukan anggota eksternal saat menambahkan anggota ke pool." msgid "" "Ability to create, update, and delete the Octavia load balancer, listener, " "pool, pool member, and health monitor resources." msgstr "" "Kemampuan untuk membuat, memperbarui, dan menghapus load balancer, " "pendengar, pool, anggota pool, dan sumber daya monitor kesehatan Octavia." msgid "" "Ability to view details of a Octavia load balancer and drill down to see " "details for the listener, pool, pool member, and health monitor resources." msgstr "" "Kemampuan untuk melihat detail dari penyeimbang beban Octavia dan menelusuri " "untuk melihat detail bagi pendengar, pool, anggota pool, dan sumber daya " "monitor kesehatan." msgid "Add load balancer flavor support." msgstr "Tambahkan dukungan penyeimbang beban." msgid "" "Added UDP protocol support in listeners and pools, added UDP-CONNECT method " "for health-monitor resources." msgstr "" "Menambahkan dukungan protokol UDP di listeners dan pools, menambahkan " "metode UDP-CONNECT untuk sumber daya health-monito." msgid "Adds L7 policy support to the dashboard." msgstr "Menambahkan dukungan kebijakan L7 ke dasbor." msgid "Adds RBAC support to the dashboard panels." msgstr "Menambahkan dukungan RBAC ke panel dasbor." msgid "" "Adds a new UI component which works as a standard select control " "alternative. Options in the component are presented in a table which may be " "filtered using the select input field. Filtering is done across all table " "fields." msgstr "" "Menambahkan komponen UI baru yang berfungsi sebagai alternatif kontrol pilih " "standar. Opsi dalam komponen disajikan dalam tabel yang dapat difilter " "menggunakan field input pilih. Pemfilteran dilakukan di semua field tabel." msgid "Adds the ability to auto refresh detail pages upon action." msgstr "" "Menambahkan kemampuan untuk me-refresh halaman detail secara otomatis saat " "beraksi." msgid "Adds the ability to set member as backup." msgstr "Menambahkan kemampuan untuk mengatur anggota sebagai cadangan." msgid "" "Adds the ability to set the X-Forwarded-Proto insertion header on listeners." msgstr "" "Menambahkan kemampuan untuk mengatur header penyisipan X-Forwarded-Proto " "pada pendengar." msgid "Adds the ability to set the insertion headers on listeners." msgstr "Menambahkan kemampuan untuk mengatur header penyisipan pada pendengar." msgid "Adds the ability to set the timeout options on listeners." msgstr "Menambahkan kemampuan untuk mengatur opsi timeout pada pendengar." msgid "All objects now allow setting the \"Admin State\"." msgstr "Semua objek sekarang memungkinkan pengaturan \"Admin State\"." msgid "Allow cascade deletion of load balancer." msgstr "Izinkan penghapusan cascade penyeimbang beban." msgid "Bug Fixes" msgstr "Perbaikan Bug" msgid "Created at and Updated at times are now visible on the details pages." msgstr "" "Dibuat dan Diperbarui pada waktu sekarang terlihat pada halaman detail." msgid "Current Series Release Notes" msgstr "Catatan Rilis Seri Saat Ini" msgid "Fixed an issue where TERMINATED_HTTPS listener type was greyed out." msgstr "" "Memperbaiki masalah ketika TERMINATED_HTTPS jenis pendengar berwarna kelabu." msgid "" "Fixes an issue in the Octavia dashboard where users receive a 403 error when " "attempting to create a load balancer. This was due to the dashboard " "attempting to access the flavor profile information which is an " "administrator only object by default." msgstr "" "Memperbaiki masalah di dasbor Octavia tempat pengguna menerima kesalahan 403 " "saat mencoba membuat penyeimbang beban. Ini disebabkan oleh dasbor yang " "mencoba mengakses informasi profil flavor yang merupakan objek hanya " "administrator secara default." msgid "Health monitors can now change the expected HTTP codes." msgstr "Monitor kesehatan sekarang dapat mengubah kode HTTP yang diharapkan." msgid "Health monitors can now use alternate IP addresses and ports." msgstr "" "Monitor kesehatan sekarang dapat menggunakan alamat IP dan port alternatif." msgid "Known Issues" msgstr "Known Issues" msgid "Listener connection limits can now be updated." msgstr "Batas koneksi pendengar sekarang dapat diperbarui." msgid "Members now display the subnet_id on the details page." msgstr "Anggota sekarang menampilkan subnet_id di halaman detail." msgid "New Features" msgstr "Fitur baru" msgid "Octavia Dashboard Release Notes" msgstr "Catatan Rilis Octavia Dashboard" msgid "Other Notes" msgstr "Catatan Lain" msgid "" "Pools attached to a load balancer are now listed on the load balancer " "details page." msgstr "" "Pools yang dilampirkan pada load balancing kini tercantum di laman detail " "load balancer." msgid "Pools can now change the load balancing algorithm after creation." msgstr "" "Pools sekarang dapat mengubah algoritma load balancing setelah penciptaan." msgid "Prelude" msgstr "Prelude" msgid "" "Provisioning and operating status is now available on all object details " "pages." msgstr "" "Status penyediaan dan pengoperasian sekarang tersedia di semua halaman " "detail objek." msgid "Queens Series Release Notes" msgstr "Catatan Rilis Seri Queens" msgid "" "RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC " "in the dashboard or not, the API RBAC will still be in effect. Enabling RBAC " "in the dashboard will enforce the policies in the dashboard before the API " "call is made." msgstr "" "RBAC sekarang dapat diaktifkan untuk dashboard Octavia. Apakah Anda " "mengaktifkan RBAC di dasbor atau tidak, API RBAC akan tetap berlaku. " "Mengaktifkan RBAC di dasbor akan menerapkan kebijakan di dasbor sebelum " "panggilan API dibuat." msgid "Rocky Series Release Notes" msgstr "Catatan Rilis Seri Rocky" msgid "Security Issues" msgstr "Masalah Keamanan" msgid "Stein Series Release Notes" msgstr "Catatan Rilis Seri Stein" msgid "" "The Octavia team is excited to release the 1.0.0 version of the Octavia " "dashboard. This dashboard uses the Octavia API endpoint via the " "openstacksdk. This release includes a number of improvements over the old " "neutron-lbaas-dashboard that worked against the neutron API endpoint. These " "improvements are listed below in the features section of this release note." msgstr "" "Tim Octavia bersemangat untuk merilis versi 1.0.0 dari dashboard Octavia. " "Dasbor ini menggunakan endpoint API Octavia melalui openstacksdk. Rilis ini " "mencakup sejumlah perbaikan atas neutron-lbaas-dashboard lama yang bekerja " "dengan endpoint API neutron. Perbaikan ini tercantum di bawah ini di bagian " "fitur dari catatan rilis ini." msgid "" "The neutron-lbaas neutron extension is not required to use this dashboard. " "Load balancers created with neutron-lbaas that have not been migrated to " "Octavia may not be accessible via this dashboard. Only resources accessible " "via the Octavia API will be visible in this dashboard." msgstr "" "Ekstensi neutron-lbaas neutron tidak diperlukan untuk menggunakan dasbor " "ini. Load balancer yang dibuat dengan neutron-lbaas yang belum bermigrasi ke " "Octavia mungkin tidak dapat diakses melalui dasbor ini. Hanya sumber daya " "yang dapat diakses melalui Octavia API yang akan terlihat di dasbor ini." msgid "" "The new component replaces the standard select for subnet selection in the " "Load Balancer creation modal wizard." msgstr "" "Komponen baru menggantikan pemilihan standar untuk pemilihan subnet dalam " "panduan modal (modal wizard) pembuatan Load Balancer." msgid "The object details pages now use a tabbed navigation for child objects." msgstr "" "Detail objek halaman sekarang menggunakan navigasi tab untuk objek anak." msgid "" "The octavia-dashboard requires openstacksdk > 0.24.0 for flavor support." msgstr "" "Octavia-dashboard membutuhkan openstacksdk > 0.24.0 untuk dukungan flavor." msgid "" "The octavia-dashboard requires openstacksdk >= 0.10.0 to resolve an issue " "with displaying the health monitor details page. It is expected this will be " "included in the OpenStack Queens release." msgstr "" "Dasbor-octavia membutuhkan openstackdk> = 0.10.0 untuk menyelesaikan masalah " "dengan menampilkan halaman rincian monitor kesehatan. Diharapkan ini akan " "dimasukkan dalam rilis OpenStack Queens." msgid "" "The pool name is now visible in pool selection drop downs in addition to the " "pool ID." msgstr "Nama pool sekarang terlihat di drop down pilihan pool selain ID pool." msgid "The session persistence for a pool can now be changed." msgstr "Persistensi sesi untuk pool sekarang dapat diubah." msgid "" "This changed the default behavior of load balancer deletion from non-cascade " "deletion to cascade deletion." msgstr "" "Ini mengubah perilaku default penghapusan penyeimbang beban dari penghapusan " "non-cascade menjadi penghapusan cascade." msgid "" "This dashboard can be used alongside the neutron-lbaas-dashboard, but both " "dashboard panels will use the \"Load Balancer\" labels." msgstr "" "Dasbor ini dapat digunakan bersama netron-lbaas-dashboard, tetapi kedua " "panel dasbor akan menggunakan label \"Load Balancer\"." msgid "" "To enable RBAC support in the Octavia dashboard you need to install the " "generated octavia_dashboard/conf/octavia_policy.yaml file into your horizon " "openstack_dashboard/conf/ directory and also copy octavia_dashboard/" "local_settings.d/_1499_load_balancer_settings.py file into your horizon " "openstack_dashboard/local/local_settings.d/ directory." msgstr "" "Untuk mengaktifkan dukungan RBAC di dasbor Octavia, Anda perlu menginstal " "file octavia_dashboard/conf/octavia_policy.yaml ke dalam direktori horizon " "openstack_dashboard/conf/ dan juga menyalin file octavia_dashboard/" "local_settings.d/_1499_load_balancer_settings.py ke dalam direktori horizon " "openstack_dashboard/local/local_settings.d/." msgid "Upgrade Notes" msgstr "Catatan Upgrade" msgid "You can now change the default pool on listeners." msgstr "Anda sekarang dapat mengubah pool default pada pendengar (listeners)." ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751924542.460101 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/ko_KR/0000775000175100017510000000000015033037476023447 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/ko_KR/LC_MESSAGES/0000775000175100017510000000000015033037476025234 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po0000664000175100017510000003126015033037474030265 0ustar00mylesmyles# ByungYeol Woo , 2018. #zanata # Ian Y. Choi , 2018. #zanata # Jaewook Oh , 2018. #zanata # ByungYeol Woo , 2019. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-10-23 02:50+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2019-10-02 04:10+0000\n" "Last-Translator: ByungYeol Woo \n" "Language-Team: Korean (South Korea)\n" "Language: ko_KR\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "1.0.0" msgstr "1.0.0" msgid "1.0.2" msgstr "1.0.2" msgid "2.0.0" msgstr "2.0.0" msgid "2.0.1" msgstr "2.0.1" msgid "3.0.0" msgstr "3.0.0" msgid "3.0.1" msgstr "3.0.1" msgid "" "A new dashboard wizard for Octavia. Allows you to create an Octavia load " "balancer and related resources such as a listener, pool, pool members, and " "health monitor." msgstr "" "Octavia를 위한 새로운 대시보드 마법사입니다. Octavia 로드 밸런서와 리스너, " "풀, 풀 멤버, 상태 모니터와 같은 연관된 리소스를 생성할 수 있습니다." msgid "A view of all the existing Octavia load balancers." msgstr "기존 Octavia 로드 밸런서를 모두 볼 수 있습니다." msgid "" "Ability to associate and disassociate floating IP addresses for a load " "balancer." msgstr "로드 밸런서에 floating IP를 연결하거나 연결 해제할 수 있습니다." msgid "" "Ability to choose from SSL certificates stored by the key-manager service " "when creating a listener using the TERMINATED_HTTPS protocol." msgstr "" "TERMINATED_HTTPS 프로토콜을 사용하여, 리스너를 생성할 때 키 관리자 서비스가 " "저장하는 SSL 인증서 중에서 선택할 수 있습니다." msgid "" "Ability to choose from existing instances from the compute service or " "specify external members when adding members to a pool." msgstr "" "컴퓨팅 서비스에서 기존 인스턴스를 선택하거나 풀에 멤버를 추가할 때 외부 멤버" "를 지정할 수 있습니다." msgid "" "Ability to create, update, and delete the Octavia load balancer, listener, " "pool, pool member, and health monitor resources." msgstr "" "Octavia 로드 밸런서, 리스너, 풀, 풀 멤버, 상태 모니터 자원을 생성, 업데이트, " "삭제할 수 있습니다." msgid "" "Ability to view details of a Octavia load balancer and drill down to see " "details for the listener, pool, pool member, and health monitor resources." msgstr "" "Octavia 로드 밸런서의 세부 정보를 보고 드릴 다운하여 리스너, 풀, 풀 멤버 및 " "상태 모니터 리소스에 대한 세부 정보를 볼 수 있습니다." msgid "Add load balancer flavor support." msgstr "로드 밸런서 flavor 지원." msgid "" "Added UDP protocol support in listeners and pools, added UDP-CONNECT method " "for health-monitor resources." msgstr "" "리스너와 풀에서 UDP 프로토콜 지원이 추가되었고, 상태 모니터 자원에 UDP-" "CONNECT 방식이 추가되었습니다." msgid "Adds L7 policy support to the dashboard." msgstr "L7 정책 지원을 대시보드에 추가하였습니다." msgid "Adds RBAC support to the dashboard panels." msgstr "RBAC 지원을 대시보드 패널에 추가하였습니다." msgid "" "Adds a new UI component which works as a standard select control " "alternative. Options in the component are presented in a table which may be " "filtered using the select input field. Filtering is done across all table " "fields." msgstr "" "표준 선택 컨트롤의 대안으로 동작하는 새로운 UI 구성요소를 추가합니다. 구성요" "소의 옵션은 선택 입력 필드를 사용하여 필터될 수 있는 테이블에서 보여집니다. " "필터링은 모든 테이블 필드에서 수행됩니다." msgid "Adds the ability to auto refresh detail pages upon action." msgstr "" "동작에 따라 세부 사항 페이지에 대한 자동 갱신하는 기능을 추가하였습니다." msgid "Adds the ability to set member as backup." msgstr "멤버를 백업을 설정하는 기능을 추가하였습니다." msgid "" "Adds the ability to set the X-Forwarded-Proto insertion header on listeners." msgstr "리스너에 X-Forwarded-Proto 헤더 삽입을 설정하는 기능을 추가하였습니다." msgid "Adds the ability to set the insertion headers on listeners." msgstr "삽입 헤더를 리스너에 설정하는 기능을 추가하였습니다." msgid "Adds the ability to set the timeout options on listeners." msgstr "타임아웃 옵션을 리스터에 설정하는 기능을 추가하였습니다." msgid "All objects now allow setting the \"Admin State\"." msgstr "이제 모든 오브젝트가 \"Admin State\"를 설정할 수 있습니다." msgid "Allow cascade deletion of load balancer." msgstr "로드 밸런서의 단계적 삭제를 허용합니다." msgid "Bug Fixes" msgstr "버그 수정" msgid "Created at and Updated at times are now visible on the details pages." msgstr "이제 생성된 시각과 업데이트된 시각을 상세 페이지에서 볼 수 있습니다." msgid "Current Series Release Notes" msgstr "최신 시리즈에 대한 릴리즈 노트" msgid "Fixed an issue where TERMINATED_HTTPS listener type was greyed out." msgstr "" "TERMINATED_HTTPS 리스너 유형이 회색으로 표시되는 문제가 해결되었습니다." msgid "" "Fixes an issue in the Octavia dashboard where users receive a 403 error when " "attempting to create a load balancer. This was due to the dashboard " "attempting to access the flavor profile information which is an " "administrator only object by default." msgstr "" "유저가 로드밸런서를 생성하려고 할 때 403 에러를 수신하는 Octavia 대시보드 문" "제를 수정하였습니다. 이는 대시보드가 기본적으로 관리자 전용 오브젝트인 " "flavor 프로파일 정보에 접근하려고 시도하기 때문입니다." msgid "Health monitors can now change the expected HTTP codes." msgstr "이제 상태 모니터는 예상되는 HTTP 코드를 바꿀 수 있습니다." msgid "Health monitors can now use alternate IP addresses and ports." msgstr "이제 상태 모니터는 다른 IP 주소와 포트를 사용할 수 있습니다." msgid "Known Issues" msgstr "알려진 이슈" msgid "Listener connection limits can now be updated." msgstr "이제 리스너 연결 제한을 업데이트할 수 있습니다." msgid "Members now display the subnet_id on the details page." msgstr "이제 멤버는 상세 페이지에서 subnet_id를 보여줍니다." msgid "New Features" msgstr "새로운 기능" msgid "Octavia Dashboard Release Notes" msgstr "Octavia 대시보드 릴리즈 노트" msgid "Other Notes" msgstr "기타 노트" msgid "" "Pools attached to a load balancer are now listed on the load balancer " "details page." msgstr "" "로드 밸런서에 연결된 포트 목록을 로그 밸런서 세부 사항 페이지에서 볼 수 있습" "니다." msgid "Pools can now change the load balancing algorithm after creation." msgstr "이제 풀은 생성 후에 로드 밸런싱 알고리즘을 변경할 수 있습니다." msgid "Prelude" msgstr "서문" msgid "" "Provisioning and operating status is now available on all object details " "pages." msgstr "" "이제 프로비저닝 상태와 작동 상태를 모든 오브젝트 상세 페이지에서 볼 수 있습니" "다." msgid "Queens Series Release Notes" msgstr "Queens 시리즈 릴리즈 노트" msgid "" "RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC " "in the dashboard or not, the API RBAC will still be in effect. Enabling RBAC " "in the dashboard will enforce the policies in the dashboard before the API " "call is made." msgstr "" "이제 RBAC를 Octavia 대시보드에서 활성화할 수 있습니다. RBAC를 대시보드에서 활" "성화를 하던 그렇지 않던, API RBAC는 여전히 동작할 것입니다. RBAC를 대시보드에" "서 활성화하면 API 요청이 만들어지기 이전에 대시보드에서 정책을 집행할 것입니" "다." msgid "Rocky Series Release Notes" msgstr "Rocky 시리즈 릴리즈 노트" msgid "Security Issues" msgstr "보안 이슈" msgid "Stein Series Release Notes" msgstr "Stein 시리즈 릴리즈 노트" msgid "" "The Octavia team is excited to release the 1.0.0 version of the Octavia " "dashboard. This dashboard uses the Octavia API endpoint via the " "openstacksdk. This release includes a number of improvements over the old " "neutron-lbaas-dashboard that worked against the neutron API endpoint. These " "improvements are listed below in the features section of this release note." msgstr "" "Octavia 팀은 1.0.0 버전의 Octavia 대시보드를 릴리즈하게 되어 기쁩니다. 이 대" "시보드는 openstacksdk를 통해 Octavia API endpoint를 이용합니다. 이번 릴리즈" "는 neutron API endpoint에 대해 작동했던 이전의 neutron-lbaas-dashboard보다 " "더 많은 개선 사항을 포함하고 있습니다. 이러한 개선 사항들은 이번 릴리즈 노트" "의 특징 섹션에서 찾아볼 수 있습니다." msgid "" "The neutron-lbaas neutron extension is not required to use this dashboard. " "Load balancers created with neutron-lbaas that have not been migrated to " "Octavia may not be accessible via this dashboard. Only resources accessible " "via the Octavia API will be visible in this dashboard." msgstr "" "이 대시보드는 neutron-lbaas neutron 익스텐션을 필요로 하지 않습니다. Octavia" "로 마이그레이션되지 않은 neutron-lbaas로 만든 로드 밸런서는이 대시보드를 통" "해 액세스 할 수 없습니다. 이 대시보드에는 Octavia API를 통해 액세스 할 수 있" "는 리소스만 표시됩니다." msgid "" "The new component replaces the standard select for subnet selection in the " "Load Balancer creation modal wizard." msgstr "" "새로운 구성요소는 로드 밸런서 생성 양식 마법사에서 서브넷 선택을 위한 표준 선" "택을 대체합니다." msgid "The object details pages now use a tabbed navigation for child objects." msgstr "이제 오브젝트 상세 페이지는 자식 오브젝트에 대해 탭 검색이 가능합니다." msgid "" "The octavia-dashboard requires openstacksdk > 0.24.0 for flavor support." msgstr "" "octavia-dashboard는 flavor 지원을 위해 openstacksdk > 0.24.0이 필요합니다." msgid "" "The octavia-dashboard requires openstacksdk >= 0.10.0 to resolve an issue " "with displaying the health monitor details page. It is expected this will be " "included in the OpenStack Queens release." msgstr "" "octavia-dashboard는 상태 모니터 상세 페이지를 표시하는데 있어 이슈를 해결하" "기 위해 openstacksdk >= 0.10.0 을 필요로 합니다. 이것은 OpenStack Queens 릴리" "즈에 포함될 것입니다." msgid "" "The pool name is now visible in pool selection drop downs in addition to the " "pool ID." msgstr "풀 선택 드롭다운에서 풀 ID 뿐만이 아니라 풀 이름도 볼 수 있습니다." msgid "The session persistence for a pool can now be changed." msgstr "이제 풀에 대한 세션 지속성을 변경할 수 있습니다." msgid "" "This changed the default behavior of load balancer deletion from non-cascade " "deletion to cascade deletion." msgstr "" "이로 인하여 로드밸런서 삭제의 기본 동작이 비 단계별 삭제에서 단계별 삭제로 변" "경되었습니다." msgid "" "This dashboard can be used alongside the neutron-lbaas-dashboard, but both " "dashboard panels will use the \"Load Balancer\" labels." msgstr "" "대시보드는 neutron-lbaas-dashboard와 함께 사용될 수 있습니다. 그러나 두 대시" "보드 패널 모두 \"Load Balancer\" 라벨을 사용할 것입니다." msgid "" "To enable RBAC support in the Octavia dashboard you need to install the " "generated octavia_dashboard/conf/octavia_policy.yaml file into your horizon " "openstack_dashboard/conf/ directory and also copy octavia_dashboard/" "local_settings.d/_1499_load_balancer_settings.py file into your horizon " "openstack_dashboard/local/local_settings.d/ directory." msgstr "" "옥타비아 대시보드에서 RBAC 지원을 활성화하려면 생성된 octavia_dashboard/conf/" "octavia_policy.yaml 파일을 호라이즌 openstack_dashboard/conf/ directory에 복" "사하고 octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py 파" "일을 openstack_dashboard/local/local_settings.d/ 디렉토리로 복사해야 합니다." msgid "Upgrade Notes" msgstr "업그레이드 노트" msgid "You can now change the default pool on listeners." msgstr "리스너에서 디폴트 풀을 이제 변경할 수 있습니다." ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4611008 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/zh_CN/0000775000175100017510000000000015033037476023443 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/zh_CN/LC_MESSAGES/0000775000175100017510000000000015033037476025230 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/zh_CN/LC_MESSAGES/releasenotes.po0000664000175100017510000001747715033037474030277 0ustar00mylesmyles# Jacky Hu , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-08-30 22:04+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-06-03 09:44+0000\n" "Last-Translator: Copied by Zanata \n" "Language-Team: Chinese (China)\n" "Language: zh_CN\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "1.0.0" msgstr "1.0.0" msgid "" "A new dashboard wizard for Octavia. Allows you to create an Octavia load " "balancer and related resources such as a listener, pool, pool members, and " "health monitor." msgstr "" "一个新的 Octavia 控制面板. 允许你创建一个 Octavia 负载均衡器及相关的资源例如" "监听器,资源池,成员和健康监控。" msgid "A view of all the existing Octavia load balancers." msgstr "一个已创建的 Octavia 负载均衡器的视图。" msgid "" "Ability to associate and disassociate floating IP addresses for a load " "balancer." msgstr "允许关联和解除关联在一个负载均衡器上的浮动 IP。" msgid "" "Ability to choose from SSL certificates stored by the key-manager service " "when creating a listener using the TERMINATED_HTTPS protocol." msgstr "" "允许选择 key-manager 服务中存储的 SSL 证书来创建 TERMINATED_HTTPS 协议的监听" "器。" msgid "" "Ability to choose from existing instances from the compute service or " "specify external members when adding members to a pool." msgstr "允许从计算服务里的已有实例和指定外部成员中选择要向资源池中添加的成员。" msgid "" "Ability to create, update, and delete the Octavia load balancer, listener, " "pool, pool member, and health monitor resources." msgstr "" "允许创建,更新和删除 Octavia 负载均衡器,监听器,资源池及成员和健康监控资源。" msgid "" "Ability to view details of a Octavia load balancer and drill down to see " "details for the listener, pool, pool member, and health monitor resources." msgstr "" "允许查看 Octavia 负载均衡器的详情,及下拉菜单查看监听器,资源池及成员和健康监" "控资源的详情。" msgid "Adds L7 policy support to the dashboard." msgstr "添加对七层策略的支持到控制面板。" msgid "Adds RBAC support to the dashboard panels." msgstr "添加 RBAC 的支持到控制面板。" msgid "Adds the ability to set the insertion headers on listeners." msgstr "允许插入报头到监听器。" msgid "All objects now allow setting the \"Admin State\"." msgstr "允许所有资源设置管理状态。" msgid "Created at and Updated at times are now visible on the details pages." msgstr "创建和更新时间现在在详情页可见。" msgid "Current Series Release Notes" msgstr "当前版本信息" msgid "Health monitors can now change the expected HTTP codes." msgstr "允许健康监控改变期待 HTTP 返回码。" msgid "Health monitors can now use alternate IP addresses and ports." msgstr "健康监控现在可以使用外部的 IP 地址和端口。" msgid "Known Issues" msgstr "已知错误" msgid "Listener connection limits can now be updated." msgstr "监听器连接限制现在可以被更新。" msgid "Members now display the subnet_id on the details page." msgstr "成员在详情页面现在可显示子网号。" msgid "New Features" msgstr "新功能" msgid "Octavia Dashboard Release Notes" msgstr "Octavia 控制面板版本信息" msgid "Other Notes" msgstr "其他信息" msgid "" "Pools attached to a load balancer are now listed on the load balancer " "details page." msgstr "负载均衡起关联的资源池现在被列出在其详情页面。" msgid "Pools can now change the load balancing algorithm after creation." msgstr "资源池现在可以在创建后更改负载均衡算法。" msgid "Prelude" msgstr "序言" msgid "" "Provisioning and operating status is now available on all object details " "pages." msgstr "配置状态和操作状态在所有资源详情页面可用。" msgid "Queens Series Release Notes" msgstr "Queens 版本信息" msgid "" "RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC " "in the dashboard or not, the API RBAC will still be in effect. Enabling RBAC " "in the dashboard will enforce the policies in the dashboard before the API " "call is made." msgstr "" "RBAC 现在可以在 Octavia 控制面板被启用。不管你是否已在控制面板中启用 RBAC," "RBAC API 都生效。在控制面板中启用使其在 API 调用之前强制执行 RBAC 策略。" msgid "Security Issues" msgstr "安全信息" msgid "" "The Octavia team is excited to release the 1.0.0 version of the Octavia " "dashboard. This dashboard uses the Octavia API endpoint via the " "openstacksdk. This release includes a number of improvements over the old " "neutron-lbaas-dashboard that worked against the neutron API endpoint. These " "improvements are listed below in the features section of this release note." msgstr "" "Octavia 团队很荣幸的分布 Octavia 控制面板 1.0.0 版本。该控制面板通过 " "openstacksdk 调用 Octavia API。该版本包含针对老的 neutron-lbaas-dashboard 的" "一系列改进。这些改进被列在发布信息的功能章节。" msgid "" "The neutron-lbaas neutron extension is not required to use this dashboard. " "Load balancers created with neutron-lbaas that have not been migrated to " "Octavia may not be accessible via this dashboard. Only resources accessible " "via the Octavia API will be visible in this dashboard." msgstr "" "当使用该控制面板时不需要 neutron 的 neutron-lbaas 插件。在 neutron-lbaas 中创" "建没有迁移到 Octavia 中的负载均衡器不一定能在该控制面板中访问。仅当其能通过 " "Octavia API 访问时才能在该控制面板中可见。" msgid "The object details pages now use a tabbed navigation for child objects." msgstr "资源详情页面通过标签导航栏来访问子资源。" msgid "" "The octavia-dashboard requires openstacksdk >= 0.10.0 to resolve an issue " "with displaying the health monitor details page. It is expected this will be " "included in the OpenStack Queens release." msgstr "" "该项目需要 openstacksdk >= 0.10.0 来解决一个健康监控详情页面的显示问题。预期" "它将包含在 OpenStack Queens 版本中。" msgid "" "The pool name is now visible in pool selection drop downs in addition to the " "pool ID." msgstr "在资源池选择下拉菜单中除了资源池 ID 外资源池名称现在也可见。" msgid "The session persistence for a pool can now be changed." msgstr "资源池的会话持久化选项现在可以被更改。" msgid "" "This dashboard can be used alongside the neutron-lbaas-dashboard, but both " "dashboard panels will use the \"Load Balancer\" labels." msgstr "" "该面板可以和 neutron-lbaas-dashboard 同时使用,两者都将使用 “负载均衡器”标" "签。" msgid "" "To enable RBAC support in the Octavia dashboard you need to install the " "generated octavia_dashboard/conf/octavia_policy.yaml file into your horizon " "openstack_dashboard/conf/ directory and also copy octavia_dashboard/" "local_settings.d/_1499_load_balancer_settings.py file into your horizon " "openstack_dashboard/local/local_settings.d/ directory." msgstr "" "要在 Octavia 控制面板中启用 RBAC 支持,你需要把生成的 octavia_dashboard/conf/" "octavia_policy.yaml 文件拷贝到 horizon 的 openstack_dashboard/conf/ 目录,并" "将 octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py 文件拷" "贝到 horizon 的 openstack_dashboard/local/local_settings.d/ directory 目录。" msgid "Upgrade Notes" msgstr "升级信息" msgid "You can now change the default pool on listeners." msgstr "允许改变监听器的默认资源池。" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4611008 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/zh_TW/0000775000175100017510000000000015033037476023475 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/zh_TW/LC_MESSAGES/0000775000175100017510000000000015033037476025262 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/locale/zh_TW/LC_MESSAGES/releasenotes.po0000664000175100017510000001750215033037474030316 0ustar00mylesmyles# Jacky Hu , 2018. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-08-30 22:04+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2018-06-03 09:46+0000\n" "Last-Translator: Copied by Zanata \n" "Language-Team: Chinese (China)\n" "Language: zh_TW\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "1.0.0" msgstr "1.0.0" msgid "" "A new dashboard wizard for Octavia. Allows you to create an Octavia load " "balancer and related resources such as a listener, pool, pool members, and " "health monitor." msgstr "" "一個新的 Octavia 控製麵板. 允許你創建一個 Octavia 負載均衡器及相關的資源例如" "監聽器,資源池,成員和健康監控。" msgid "A view of all the existing Octavia load balancers." msgstr "一個已創建的 Octavia 負載均衡器的視圖。" msgid "" "Ability to associate and disassociate floating IP addresses for a load " "balancer." msgstr "允許關聯和解除關聯在一個負載均衡器上的浮動 IP。" msgid "" "Ability to choose from SSL certificates stored by the key-manager service " "when creating a listener using the TERMINATED_HTTPS protocol." msgstr "" "允許選擇 key-manager 服務中存儲的 SSL 證書來創建 TERMINATED_HTTPS 協議的監聽" "器。" msgid "" "Ability to choose from existing instances from the compute service or " "specify external members when adding members to a pool." msgstr "允許從計算服務裡的已有實例和指定外部成員中選擇要向資源池中添加的成員。" msgid "" "Ability to create, update, and delete the Octavia load balancer, listener, " "pool, pool member, and health monitor resources." msgstr "" "允許創建,更新和刪除 Octavia 負載均衡器,監聽器,資源池及成員和健康監控資源。" msgid "" "Ability to view details of a Octavia load balancer and drill down to see " "details for the listener, pool, pool member, and health monitor resources." msgstr "" "允許查看 Octavia 負載均衡器的詳情,及下拉菜單查看監聽器,資源池及成員和健康監" "控資源的詳情。" msgid "Adds L7 policy support to the dashboard." msgstr "添加對七層策略的支持到控製麵板。" msgid "Adds RBAC support to the dashboard panels." msgstr "添加 RBAC 的支持到控製麵板。" msgid "Adds the ability to set the insertion headers on listeners." msgstr "允許插入報頭到監聽器。" msgid "All objects now allow setting the \"Admin State\"." msgstr "允許所有資源設置管理狀態。" msgid "Created at and Updated at times are now visible on the details pages." msgstr "創建和更新時間現在在詳情頁可見。" msgid "Current Series Release Notes" msgstr "當前版本信息" msgid "Health monitors can now change the expected HTTP codes." msgstr "允許健康監控改變期待 HTTP 返回碼。" msgid "Health monitors can now use alternate IP addresses and ports." msgstr "健康監控現在可以使用外部的 IP 地址和連接埠。" msgid "Known Issues" msgstr "已知錯誤" msgid "Listener connection limits can now be updated." msgstr "監聽器連接限制現在可以被更新。" msgid "Members now display the subnet_id on the details page." msgstr "成員在詳情頁面現在可顯示子網號。" msgid "New Features" msgstr "新功能" msgid "Octavia Dashboard Release Notes" msgstr "Octavia 控製麵板版本信息" msgid "Other Notes" msgstr "其他信息" msgid "" "Pools attached to a load balancer are now listed on the load balancer " "details page." msgstr "負載均衡起關聯的資源池現在被列出在其詳情頁面。" msgid "Pools can now change the load balancing algorithm after creation." msgstr "資源池現在可以在創建後更改負載均衡算法。" msgid "Prelude" msgstr "序言" msgid "" "Provisioning and operating status is now available on all object details " "pages." msgstr "配置狀態和操作狀態在所有資源詳情頁面可用。" msgid "Queens Series Release Notes" msgstr "Queens 版本信息" msgid "" "RBAC can now be enabled for the Octavia dashboard. Whether you enable RBAC " "in the dashboard or not, the API RBAC will still be in effect. Enabling RBAC " "in the dashboard will enforce the policies in the dashboard before the API " "call is made." msgstr "" "RBAC 現在可以在 Octavia 控製麵板被啟用。不管你是否已在控製麵板中啟用 RBAC," "RBAC API 都生效。在控製麵板中啟用使其在 API 調用之前強制執行 RBAC 策略。" msgid "Security Issues" msgstr "安全信息" msgid "" "The Octavia team is excited to release the 1.0.0 version of the Octavia " "dashboard. This dashboard uses the Octavia API endpoint via the " "openstacksdk. This release includes a number of improvements over the old " "neutron-lbaas-dashboard that worked against the neutron API endpoint. These " "improvements are listed below in the features section of this release note." msgstr "" "Octavia 團隊很榮幸的分佈 Octavia 控製麵板 1.0.0 版本。該控製麵板通過 " "openstacksdk 調用 Octavia API。該版本包含針對老的 neutron-lbaas-dashboard 的" "一系列改進。這些改進被列在發佈信息的功能章節。" msgid "" "The neutron-lbaas neutron extension is not required to use this dashboard. " "Load balancers created with neutron-lbaas that have not been migrated to " "Octavia may not be accessible via this dashboard. Only resources accessible " "via the Octavia API will be visible in this dashboard." msgstr "" "當使用該控製麵板時不需要 neutron 的 neutron-lbaas 插件。在 neutron-lbaas 中創" "建沒有遷移到 Octavia 中的負載均衡器不一定能在該控製麵板中訪問。僅當其能通過 " "Octavia API 訪問時才能在該控製麵板中可見。" msgid "The object details pages now use a tabbed navigation for child objects." msgstr "資源詳情頁面通過標籤導航欄來訪問子資源。" msgid "" "The octavia-dashboard requires openstacksdk >= 0.10.0 to resolve an issue " "with displaying the health monitor details page. It is expected this will be " "included in the OpenStack Queens release." msgstr "" "該項目需要 openstacksdk >= 0.10.0 來解決一個健康監控詳情頁面的顯示問題。預期" "它將包含在 OpenStack Queens 版本中。" msgid "" "The pool name is now visible in pool selection drop downs in addition to the " "pool ID." msgstr "在資源池選擇下拉菜單中除了資源池 ID 外資源池名稱現在也可見。" msgid "The session persistence for a pool can now be changed." msgstr "資源池的會話持久化選項現在可以被更改。" msgid "" "This dashboard can be used alongside the neutron-lbaas-dashboard, but both " "dashboard panels will use the \"Load Balancer\" labels." msgstr "" "該面板可以和 neutron-lbaas-dashboard 同時使用,兩者都將使用 “負載均衡器”標" "籤。" msgid "" "To enable RBAC support in the Octavia dashboard you need to install the " "generated octavia_dashboard/conf/octavia_policy.yaml file into your horizon " "openstack_dashboard/conf/ directory and also copy octavia_dashboard/" "local_settings.d/_1499_load_balancer_settings.py file into your horizon " "openstack_dashboard/local/local_settings.d/ directory." msgstr "" "要在 Octavia 控製麵板中啟用 RBAC 支持,你需要把生成的 octavia_dashboard/conf/" "octavia_policy.yaml 檔案拷貝到 horizon 的 openstack_dashboard/conf/ 目錄,並" "將 octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py 檔案拷" "貝到 horizon 的 openstack_dashboard/local/local_settings.d/ directory 目錄。" msgid "Upgrade Notes" msgstr "升級信息" msgid "You can now change the default pool on listeners." msgstr "允許改變監聽器的預設資源池。" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/queens.rst0000664000175100017510000000022315033037474023230 0ustar00mylesmyles=================================== Queens Series Release Notes =================================== .. release-notes:: :branch: stable/queens ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/rocky.rst0000664000175100017510000000022115033037474023055 0ustar00mylesmyles=================================== Rocky Series Release Notes =================================== .. release-notes:: :branch: stable/rocky ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/stein.rst0000664000175100017510000000022115033037474023050 0ustar00mylesmyles=================================== Stein Series Release Notes =================================== .. release-notes:: :branch: stable/stein ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/train.rst0000664000175100017510000000017615033037474023054 0ustar00mylesmyles========================== Train Series Release Notes ========================== .. release-notes:: :branch: stable/train ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/unreleased.rst0000664000175100017510000000016015033037474024057 0ustar00mylesmyles============================== Current Series Release Notes ============================== .. release-notes:: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/ussuri.rst0000664000175100017510000000020215033037474023257 0ustar00mylesmyles=========================== Ussuri Series Release Notes =========================== .. release-notes:: :branch: stable/ussuri ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/victoria.rst0000664000175100017510000000022015033037474023545 0ustar00mylesmyles============================= Victoria Series Release Notes ============================= .. release-notes:: :branch: unmaintained/victoria ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/wallaby.rst0000664000175100017510000000021415033037474023363 0ustar00mylesmyles============================ Wallaby Series Release Notes ============================ .. release-notes:: :branch: unmaintained/wallaby ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/xena.rst0000664000175100017510000000020015033037474022656 0ustar00mylesmyles========================= Xena Series Release Notes ========================= .. release-notes:: :branch: unmaintained/xena ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/yoga.rst0000664000175100017510000000020015033037474022662 0ustar00mylesmyles========================= Yoga Series Release Notes ========================= .. release-notes:: :branch: unmaintained/yoga ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/releasenotes/source/zed.rst0000664000175100017510000000017415033037474022517 0ustar00mylesmyles======================== Zed Series Release Notes ======================== .. release-notes:: :branch: unmaintained/zed ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/requirements.txt0000664000175100017510000000057015033037474020476 0ustar00mylesmyles# Requirements lower bounds listed here are our best effort to keep them up to # date but we do not test them so no guarantee of having them all correct. If # you find any incorrect lower bounds, let us know or propose a fix. horizon>=17.1.0 # Apache-2.0 Babel>=2.3.4 # BSD openstacksdk>=0.53.0 # Apache-2.0 pbr>=2.0.0 # Apache-2.0 python-keystoneclient>=3.22.0 # Apache-2.0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4781008 octavia_dashboard-15.1.0.dev2/setup.cfg0000664000175100017510000000160015033037476017030 0ustar00mylesmyles[metadata] name = octavia-dashboard summary = Horizon panels for Octavia description_file = README.rst author = OpenStack author_email = openstack-discuss@lists.openstack.org home_page = https://docs.openstack.org/octavia-dashboard/latest/ python_requires = >=3.9 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 :: Implementation :: CPython Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 [files] packages = octavia_dashboard [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/setup.py0000664000175100017510000000127115033037474016723 0ustar00mylesmyles# 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. import setuptools setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/test-requirements.txt0000664000175100017510000000044415033037474021453 0ustar00mylesmyleshacking>=6.1.0,<6.2.0 # Apache-2.0 coverage>=4.0 # Apache-2.0 selenium>=2.50.1 # Apache-2.0 oslotest>=3.2.0 # Apache-2.0 stestr>=2.0.0 # Apache-2.0 testscenarios>=0.4 # Apache-2.0/BSD testtools>=2.2.0 # MIT # This also needs xvfb library installed on your OS xvfbwrapper>=0.1.3 #license: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/tox.ini0000664000175100017510000000427715033037474016535 0ustar00mylesmyles[tox] minversion = 3.18.0 envlist = py3,pep8,eslint,karma [testenv] usedevelop = True setenv = VIRTUAL_ENV={envdir} CLIENT_NAME=octavia-dashboard DJANGO_SETTINGS_MODULE=octavia_dashboard.tests.settings deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt allowlist_externals = npm bash commands = python manage.py test octavia_dashboard --settings=octavia_dashboard.tests.settings [testenv:pep8] commands = flake8 [testenv:venv] commands = {posargs} [testenv:cover] # npm must be installed on the system, for example # sudo apt-get install npm # sudo yum install npm (on RHEL/CentOS, enable EPEL repository) commands = npm install npm test [testenv:docs] allowlist_externals = rm deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/requirements.txt -r{toxinidir}/doc/requirements.txt commands = rm -rf doc/build/html sphinx-build -W -b html doc/source doc/build/html [testenv:pdf-docs] deps = {[testenv:docs]deps} allowlist_externals = make rm commands = rm -rf doc/build/pdf sphinx-build -W -b latex doc/source doc/build/pdf make -C doc/build/pdf [testenv:releasenotes] allowlist_externals = rm deps = {[testenv:docs]deps} commands = rm -rf releasenotes/build sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html [testenv:debug] commands = oslo_debug_helper {posargs} [testenv:eslint] # npm must be installed on the system, for example # sudo apt-get install npm commands = npm install npm run lint [testenv:karma] # npm must be installed on the system, for example # sudo apt-get install npm commands = npm install npm test [flake8] # E123, E125 skipped as they are invalid PEP-8. # F405 TEMPLATES may be undefined, or defined from star imports # W504 line break after binary operator # (because it is not easy to avoid this in openstack_dashboard.test.settings) show-source = True ignore = E123,E125,F405,W504 builtins = _ exclude=.venv,.git,.tox,.tmp,dist,doc,*lib/python*,*egg,build,node_modules ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751924542.4771006 octavia_dashboard-15.1.0.dev2/zuul.d/0000775000175100017510000000000015033037476016433 5ustar00mylesmyles././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751924540.0 octavia_dashboard-15.1.0.dev2/zuul.d/projects.yaml0000664000175100017510000000040615033037474021146 0ustar00mylesmyles- project: templates: - check-requirements - horizon-non-primary-django-jobs - horizon-nodejs-jobs - openstack-python3-jobs-horizon - publish-openstack-docs-pti - release-notes-jobs-python3 gate: fail-fast: true