././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0880096 octavia-dashboard-4.1.0.dev21/0000755000175000017500000000000000000000000016274 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/.coveragerc0000644000175000017500000000011600000000000020413 0ustar00coreycorey00000000000000[run] branch = True source = octavia_dashboard [report] ignore_errors = True ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/.eslintrc0000644000175000017500000000263400000000000020125 0ustar00coreycorey00000000000000# 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/.mailmap0000644000175000017500000000013100000000000017710 0ustar00coreycorey00000000000000# Format is: # # ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/.stestr.conf0000644000175000017500000000011300000000000020540 0ustar00coreycorey00000000000000[DEFAULT] test_path=${OS_TEST_PATH:-./octavia_dashboard/tests/} top_dir=./ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806715.0 octavia-dashboard-4.1.0.dev21/AUTHORS0000644000175000017500000000424000000000000017344 0ustar00coreycorey00000000000000Ajay 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 Gregory Thiemonge Jacky Hu James E. Blair Justin Pomeroy Kyle Mestery Lucas Palm MaoyangLiu Mark Vanderwiel Matt Borland Michael Johnson MinSun Monty Taylor Nguyen Hai Nir Magnezi OpenStack Release Bot Praveen Yalagandula Qian Min Chen Rajiv Kumar Sam Morrison Sean McGinnis ShangXiao Swapnil Kulkarni (coolsvap) Tong Liu 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 xuleibj ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/CONTRIBUTING.rst0000644000175000017500000000125000000000000020733 0ustar00coreycorey00000000000000If 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806715.0 octavia-dashboard-4.1.0.dev21/ChangeLog0000644000175000017500000003171000000000000020050 0ustar00coreycorey00000000000000CHANGES ======= * 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/HACKING.rst0000644000175000017500000000023400000000000020071 0ustar00coreycorey00000000000000octavia-dashboard Style Commandments ==================================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/LICENSE0000644000175000017500000002363700000000000017314 0ustar00coreycorey00000000000000 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. ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0880096 octavia-dashboard-4.1.0.dev21/PKG-INFO0000644000175000017500000000724600000000000017402 0ustar00coreycorey00000000000000Metadata-Version: 1.1 Name: octavia-dashboard Version: 4.1.0.dev21 Summary: Horizon panels for Octavia Home-page: https://docs.openstack.org/octavia-dashboard/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: ================= 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 Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/README.rst0000644000175000017500000000453600000000000017773 0ustar00coreycorey00000000000000================= 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/babel-django.cfg0000644000175000017500000000011200000000000021254 0ustar00coreycorey00000000000000[python: **.py] [django: templates/**.html] [django: **/templates/**.csv] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/babel-djangojs.cfg0000644000175000017500000000006100000000000021614 0ustar00coreycorey00000000000000[javascript: **.js] [angular: **/static/**.html] ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.012015 octavia-dashboard-4.1.0.dev21/devstack/0000755000175000017500000000000000000000000020100 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/devstack/README.rst0000644000175000017500000000134400000000000021571 0ustar00coreycorey00000000000000================================= 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/devstack/plugin.sh0000644000175000017500000000357300000000000021742 0ustar00coreycorey00000000000000function 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/devstack/settings0000644000175000017500000000005600000000000021664 0ustar00coreycorey00000000000000OCTAVIA_DASHBOARD_DIR=$DEST/octavia-dashboard ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.012015 octavia-dashboard-4.1.0.dev21/doc/0000755000175000017500000000000000000000000017041 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/doc/requirements.txt0000644000175000017500000000070000000000000022322 0ustar00coreycorey00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. openstackdocstheme>=1.20.0 # Apache-2.0 sphinx!=1.6.6,!=1.6.7,>=1.6.2,!=2.1.0;python_version>='3.4' # BSD sphinxcontrib-apidoc>=0.2.1 # BSD # releasenotes reno>=2.5.0 # Apache-2.0 # PDF Docs sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.012015 octavia-dashboard-4.1.0.dev21/doc/source/0000755000175000017500000000000000000000000020341 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/doc/source/conf.py0000755000175000017500000001214400000000000021645 0ustar00coreycorey00000000000000# -*- 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 = u'2017-2019, OpenStack Foundation' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # Version info from octavia_dashboard.version import version_info as octavia_dash_version release = octavia_dash_version.release_string() # The short X.Y version. version = octavia_dash_version.version_string() # 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 = 'sphinx' # openstackdocstheme options repository_name = 'openstack/octavia-dashboard' 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', u'Octavia Dashboard Documentation', u'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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/doc/source/contributing.rst0000644000175000017500000000011300000000000023575 0ustar00coreycorey00000000000000============ Contributing ============ .. include:: ../../CONTRIBUTING.rst ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/doc/source/index.rst0000644000175000017500000000062600000000000022206 0ustar00coreycorey00000000000000.. 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/doc/source/installation.rst0000644000175000017500000000200300000000000023567 0ustar00coreycorey00000000000000============ 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/doc/source/readme.rst0000644000175000017500000000003600000000000022327 0ustar00coreycorey00000000000000.. include:: ../../README.rst ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/doc/source/reference.rst0000644000175000017500000000042600000000000023033 0ustar00coreycorey00000000000000========= Reference ========= .. only:: latex Module Reference ---------------- .. toctree:: :hidden: contributor/modules/modules .. only:: html Indices and search ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/lower-constraints.txt0000644000175000017500000000553400000000000022541 0ustar00coreycorey00000000000000amqp==2.1.1 appdirs==1.3.0 asn1crypto==0.23.0 Babel==2.3.4 cachetools==2.0.0 cffi==1.7.0 cliff==2.8.0 cmd2==0.8.0 contextlib2==0.4.0 coverage==4.0 cryptography==2.1 debtcollector==1.2.0 decorator==3.4.0 deprecation==1.0 Django==2.2 django-appconf==1.0.2 django-babel==0.5.1 django-compressor==2.0 django-pyscss==2.0.2 dogpile.cache==0.6.2 eventlet==0.18.2 extras==1.0.0 fasteners==0.7.0 fixtures==3.0.0 flake8==2.5.5 futurist==1.2.0 greenlet==0.4.10 hacking==0.12.0 horizon==17.1.0 idna==2.6 iso8601==0.1.11 Jinja2==2.10 jmespath==0.9.0 jsonpatch==1.16 jsonpointer==1.13 jsonschema==2.6.0 keystoneauth1==3.4.0 kombu==4.0.0 linecache2==1.0.0 MarkupSafe==1.0 mccabe==0.2.1 mock==2.0.0 monotonic==0.6 mox3==0.20.0 msgpack-python==0.4.0 munch==2.1.0 netaddr==0.7.18 netifaces==0.10.4 openstacksdk==0.24.0 os-client-config==1.28.0 os-service-types==1.2.0 osc-lib==1.8.0 oslo.concurrency==3.25.0 oslo.config==5.2.0 oslo.context==2.19.2 oslo.i18n==3.15.3 oslo.log==3.36.0 oslo.messaging==5.29.0 oslo.middleware==3.31.0 oslo.policy==1.30.0 oslo.serialization==2.18.0 oslo.service==1.24.0 oslo.utils==3.33.0 oslotest==3.2.0 osprofiler==2.3.0 Paste==2.0.2 PasteDeploy==1.5.0 pbr==2.0.0 pep8==1.5.7 pika==0.10.0 pika-pool==0.1.3 Pint==0.5 positional==1.2.1 prettytable==0.7.2 pycparser==2.18 pyflakes==0.8.1 pyinotify==0.9.6 pymongo==3.0.2 pyOpenSSL==17.1.0 pyparsing==2.1.0 pyperclip==1.5.27 pyScss==1.3.7 python-barbicanclient==4.5.2 python-cinderclient==3.3.0 python-dateutil==2.5.3 python-glanceclient==2.8.0 python-keystoneclient==3.22.0 python-mimeparse==1.6.0 python-neutronclient==6.7.0 python-novaclient==9.1.0 python-subunit==1.0.0 python-swiftclient==3.2.0 pytz==2013.6 PyYAML==3.12 rcssmin==1.0.6 repoze.lru==0.7 requests==2.14.2 requestsexceptions==1.2.0 rfc3986==0.3.1 rjsmin==1.0.12 Routes==2.3.1 selenium==2.50.1 semantic-version==2.3.1 simplejson==3.5.1 six==1.10.0 statsd==3.2.1 stestr==2.0.0 stevedore==1.20.0 tenacity==3.2.1 testrepository==0.0.18 testscenarios==0.4 testtools==2.2.0 traceback2==1.4.0 unittest2==1.1.0 vine==1.1.4 warlock==1.2.0 WebOb==1.7.1 wrapt==1.7.0 XStatic==1.0.0 XStatic-Angular==1.5.8.0 XStatic-Angular-Bootstrap==2.2.0.0 XStatic-Angular-FileUpload==12.0.4.0 XStatic-Angular-Gettext==2.3.8.0 XStatic-Angular-lrdragndrop==1.0.2.2 XStatic-Angular-Schema-Form==0.8.13.0 XStatic-Bootstrap-Datepicker==1.3.1.0 XStatic-Bootstrap-SCSS==3.3.7.1 XStatic-bootswatch==3.3.7.0 XStatic-D3==3.5.17.0 XStatic-Font-Awesome==4.7.0.0 XStatic-Hogan==2.0.0.2 XStatic-Jasmine==2.4.1.1 XStatic-jQuery==1.8.2.1 XStatic-JQuery-Migrate==1.2.1.1 XStatic-jquery-ui==1.10.4.1 XStatic-JQuery.quicksearch==2.0.3.1 XStatic-JQuery.TableSorter==2.14.5.1 XStatic-JSEncrypt==2.3.1.1 XStatic-mdi==1.4.57.0 XStatic-objectpath==1.2.1.0 XStatic-Rickshaw==1.5.0.0 XStatic-roboto-fontface==0.5.0.0 XStatic-smart-table==1.4.13.2 XStatic-Spin==1.2.5.2 XStatic-term.js==0.0.7.0 XStatic-tv4==1.2.7.0 xvfbwrapper==0.1.3 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/manage.py0000644000175000017500000000150600000000000020100 0ustar00coreycorey00000000000000#!/usr/bin/env python # 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) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/0000755000175000017500000000000000000000000021731 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/__init__.py0000644000175000017500000000120700000000000024042 0ustar00coreycorey00000000000000# 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() ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/api/0000755000175000017500000000000000000000000022502 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/api/__init__.py0000644000175000017500000000000000000000000024601 0ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/api/rest/0000755000175000017500000000000000000000000023457 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/api/rest/__init__.py0000644000175000017500000000206200000000000025570 0ustar00coreycorey00000000000000# 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/api/rest/barbican.py0000644000175000017500000000600700000000000025575 0ustar00coreycorey00000000000000# 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 barbicanclient import client as barbican_client from django.conf import settings from django.views import generic from keystoneclient.auth import token_endpoint from keystoneclient import session from horizon.utils.memoized import memoized # noqa from openstack_auth import utils as auth_utils from openstack_dashboard.api import base from openstack_dashboard.api.rest import urls from openstack_dashboard.api.rest import utils as rest_utils @memoized def barbicanclient(request): region = request.user.services_region endpoint = base.url_for(request, 'key-manager') auth_url, _ = auth_utils.fix_auth_url_version_prefix( settings.OPENSTACK_KEYSTONE_URL) auth = token_endpoint.Token(auth_url, request.user.token.id) insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) # If 'insecure' is True, 'verify' is False in all cases; otherwise # pass the cacert path if it is present, or True if no cacert. verify = not insecure and (cacert or True) return barbican_client.Client(session=session.Session(auth=auth, verify=verify), endpoint=endpoint, region_name=region) @urls.register class SSLCertificates(generic.View): """API for working with SSL certificate containers. """ url_regex = r'barbican/certificates/$' @rest_utils.ajax() def get(self, request): """List certificate containers. The listing result is an object with property "items". """ limit = getattr(settings, 'API_RESULT_LIMIT', 1000) containers = barbicanclient(request).containers params = {'limit': limit, 'type': 'certificate'} result = containers._api.get('containers', params=params) return {'items': result.get('containers')} @urls.register class Secrets(generic.View): """API for working with secrets. """ url_regex = r'barbican/secrets/$' @rest_utils.ajax() def get(self, request): """List secrets. The listing result is an object with property "items". """ limit = getattr(settings, 'API_RESULT_LIMIT', 1000) secrets = barbicanclient(request).secrets params = {'limit': limit} result = secrets._api.get('secrets', params=params) return {'items': result.get('secrets')} ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/api/rest/lbaasv2.py0000644000175000017500000013330300000000000025366 0ustar00coreycorey00000000000000# 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 from time import sleep from django.conf import settings from django.views import generic from horizon import conf import octavia_dashboard from openstack import connection try: from openstack import config as occ except ImportError: from os_client_config import config as occ 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 _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, token=request.user.token.unscoped_token, auth_url=request.user.endpoint), app_name='octavia-dashboard', app_version=octavia_dashboard.__version__) return connection.from_config(cloud_config=cloud_config) 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: 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 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'), ) 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') ) 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'), ) 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') ) # 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'] conn = _get_sdk_connection(request) healthmonitor = conn.load_balancer.update_health_monitor( monitor_id, 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'), 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(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) conn.load_balancer.delete_listener(listener_id, ignore_missing=True) @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) conn.load_balancer.delete_l7_policy(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) conn.load_balancer.delete_l7_rule(l7_rule_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) conn.load_balancer.delete_pool(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) conn.load_balancer.delete_member(member_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) conn.load_balancer.delete_health_monitor(health_monitor_id, ignore_missing=True) @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} ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/conf/0000755000175000017500000000000000000000000022656 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/conf/.gitkeep0000644000175000017500000000000000000000000024275 0ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/0000755000175000017500000000000000000000000024043 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/__init__.py0000644000175000017500000000000000000000000026142 0ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/0000755000175000017500000000000000000000000025511 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/__init__.py0000644000175000017500000000000000000000000027610 0ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/0000755000175000017500000000000000000000000030257 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/__init__.py0000644000175000017500000000127100000000000032371 0ustar00coreycorey00000000000000# 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/panel.py0000644000175000017500000000150200000000000031726 0ustar00coreycorey00000000000000# (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 ugettext_lazy as _ import horizon class NGLoadBalancers(horizon.Panel): name = _("Load Balancers") slug = 'load_balancer' permissions = ('openstack.services.network',) ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/templates/0000755000175000017500000000000000000000000032255 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000115 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/templates/load_balancer/ 28 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/templates/load_bala0000755000175000017500000000000000000000000034074 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000125 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/templates/load_balancer/index.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/templates/load_bala0000644000175000017500000000046400000000000034102 0ustar00coreycorey00000000000000{% 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 %} ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/urls.py0000644000175000017500000000142700000000000031622 0ustar00coreycorey00000000000000# (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.conf.urls import url from octavia_dashboard.dashboards.project.load_balancer import views urlpatterns = [ url('', views.IndexView.as_view(), name='index'), ] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/dashboards/project/load_balancer/views.py0000644000175000017500000000142500000000000031770 0ustar00coreycorey00000000000000# (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' ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/enabled/0000755000175000017500000000000000000000000023323 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/enabled/_1482_project_load_balancer_panel.py0000644000175000017500000000225000000000000032164 0ustar00coreycorey00000000000000# 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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/enabled/__init__.py0000644000175000017500000000000000000000000025422 0ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/karma.conf.js0000644000175000017500000001223000000000000024304 0ustar00coreycorey00000000000000/* * 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 = '../.tox/karma/lib/python3.6//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: ['PhantomJS'], phantomjsLauncher: { // Have phantomjs exit if a ResourceError is encountered // (useful if karma exits without killing phantom) exitOnResourceError: true }, reporters: ['progress', 'coverage', 'threshold'], plugins: [ 'karma-phantomjs-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 } }); }; ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/local_settings.d/0000755000175000017500000000000000000000000025165 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/local_settings.d/_1499_load_balancer_settings.py0000644000175000017500000000143500000000000033055 0ustar00coreycorey00000000000000# 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', }) ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/0000755000175000017500000000000000000000000023170 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/de/0000755000175000017500000000000000000000000023560 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/de/LC_MESSAGES/0000755000175000017500000000000000000000000025345 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/de/LC_MESSAGES/django.po0000644000175000017500000000112200000000000027143 0ustar00coreycorey00000000000000# 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" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/de/LC_MESSAGES/djangojs.po0000644000175000017500000012767400000000000027525 0ustar00coreycorey00000000000000# Andreas Jaeger , 2018. #zanata # Frank Kloeker , 2018. #zanata # Robert Simai , 2018. #zanata # Andreas Jaeger , 2019. #zanata # Robert Simai , 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: 2019-09-24 10:58+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-26 06:47+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" #, 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 "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 "Gelöschte Loadbalancer" 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 protocol for which this pool and its members listen. A valid value is " "HTTP, HTTPS, PROXY, TCP or UDP." msgstr "" "Das Protokoll, auf das dieser Pool und seine Mitglieder hören. Ein gültiger " "Wert ist HTTP, HTTPS, PROXY, TCP oder UDP." 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 "The weight must be a number between 1 and 256." msgstr "Das Gewicht muss eine Zahl zwischen 1 und 256 sein." 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 higher weight means it will receive " "more traffic. Must be\n" " a number from 1 to 256." msgstr "" "Das Gewicht der Mitglieder bestimmt die Portion der Anfragen oder " "Verbindungen zum Dienst im Vergleich\n" " zu anderen Mitgliedern des Pools. Ein höheres Gewicht wird mehr Verkehr " "erzeugen. Muss eine Zahl\n" " zwischen 1 und 256 sein." 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 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." ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/en_AU/0000755000175000017500000000000000000000000024157 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/en_AU/LC_MESSAGES/0000755000175000017500000000000000000000000025744 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/en_AU/LC_MESSAGES/django.po0000644000175000017500000000116700000000000027553 0ustar00coreycorey00000000000000# 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" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/en_AU/LC_MESSAGES/djangojs.po0000644000175000017500000003441500000000000030112 0ustar00coreycorey00000000000000# Hengqing Hu , 2017. #zanata # Hengqing 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: 2018-05-09 03:37+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-22 05:04+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" #, 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 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 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 "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 Pool Members" msgstr "Add/Remove Pool Members" msgid "Admin State Up" msgstr "Admin State Up" msgid "Allocated Members" msgstr "Allocated Members" 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 "Available Instances" msgstr "Available Instances" msgid "Cancel" msgstr "Cancel" msgid "Certificate Name" msgstr "Certificate Name" #, fuzzy msgid "Confirm Delete Health Monitor" msgid_plural "Confirm Delete Health Monitors" msgstr[0] "Confirm Delete Health Monitor" msgstr[1] "" #, fuzzy msgid "Confirm Delete Member" msgid_plural "Confirm Delete Members" msgstr[0] "Confirm Delete Member" msgstr[1] "" #, fuzzy msgid "Confirm Delete Pool" msgid_plural "Confirm Delete Pools" msgstr[0] "Confirm Delete Pool" msgstr[1] "" msgid "Confirm Disassociate Floating IP Address" msgstr "Confirm Disassociate Floating IP Address" msgid "Connection Limit" msgstr "Connection Limit" msgid "Create Health Monitor" msgstr "Create Health Monitor" 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 "Degraded" msgstr "Degraded" msgid "Delay" msgstr "Delay" #, fuzzy msgid "Delete Health Monitor" msgid_plural "Delete Health Monitors" msgstr[0] "Delete Health Monitor" msgstr[1] "" #, fuzzy msgid "Delete Listener" msgid_plural "Delete Listeners" msgstr[0] "Delete Listener" msgstr[1] "" msgid "Delete Listeners" msgstr "Delete Listeners" #, fuzzy msgid "Delete Load Balancer" msgid_plural "Delete Load Balancers" msgstr[0] "Delete Load Balancer" msgstr[1] "" msgid "Delete Load Balancers" msgstr "Delete Load Balancers" #, fuzzy msgid "Delete Member" msgid_plural "Delete Members" msgstr[0] "Delete Member" msgstr[1] "" #, fuzzy msgid "Delete Pool" msgid_plural "Delete Pools" msgstr[0] "Delete Pool" msgstr[1] "" 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 "" "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 "Error" msgstr "Error" msgid "Expected Codes" msgstr "Expected Codes" msgid "Expiration Date" msgstr "Expiration Date" msgid "Floating IP addresses" msgstr "Floating IP addresses" msgid "Floating IP pools" msgstr "Floating IP pools" msgid "HTTP Method" msgstr "HTTP Method" msgid "Health Monitor ID" msgstr "Health Monitor ID" 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 "" "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 "Least Connections" msgstr "Least Connections" msgid "Listener Details" msgstr "Listener Details" msgid "Listener ID" msgstr "Listener ID" msgid "Listeners" msgstr "Listeners" 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 "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 Details" msgstr "Monitor Details" msgid "Monitor Port" msgstr "Monitor Port" msgid "Name" msgstr "Name" 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 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 "Pending Create" msgstr "Pending Create" msgid "Pending Delete" msgstr "Pending Delete" msgid "Pending Update" msgstr "Pending Update" 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 "Port" msgstr "Port" msgid "Port ID" msgstr "Port ID" msgid "Project ID" msgstr "Project ID" msgid "Protocol" msgstr "Protocol" msgid "Protocol Port" msgstr "Protocol Port" msgid "Provide the details for the health monitor." msgstr "Provide the details for the health monitor." 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 "Remove" msgstr "Remove" msgid "Round Robin" msgstr "Round Robin" msgid "SSL Certificates" msgstr "SSL Certificates" 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 "Source IP" msgstr "Source IP" msgid "Subnet ID" msgstr "Subnet ID" 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 IP address is not valid." msgstr "The IP address is not valid." msgid "The URL path is not valid." msgstr "The URL path is not valid." 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 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 listener has been updated." msgstr "The listener has been updated." 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 monitor port must be a number between 1 and 65535." msgstr "The monitor port must be a number between 1 and 65535." 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 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 weight must be a number between 1 and 256." msgstr "The weight must be a number between 1 and 256." msgid "Timeout" msgstr "Timeout" msgid "Type" msgstr "Type" msgid "URL Path" msgstr "URL Path" msgid "Unable to create health monitor." msgstr "Unable to create health monitor." 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." msgid "Unable to delete health monitor." msgstr "Unable to delete health monitor." 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 health monitor." msgstr "Unable to retrieve health monitor." 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 secrets." msgstr "Unable to retrieve secrets." msgid "Unable to update health monitor." msgstr "Unable to update health monitor." 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 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 "Weight" msgstr "Weight" #, 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." ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/en_GB/0000755000175000017500000000000000000000000024142 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/en_GB/LC_MESSAGES/0000755000175000017500000000000000000000000025727 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/en_GB/LC_MESSAGES/django.po0000644000175000017500000000115300000000000027531 0ustar00coreycorey00000000000000# 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" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/en_GB/LC_MESSAGES/djangojs.po0000644000175000017500000012167200000000000030077 0ustar00coreycorey00000000000000# Andi Chandler , 2017. #zanata # Jacky Hu , 2017. #zanata # Andi Chandler , 2018. #zanata # Andi Chandler , 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: 2019-10-29 15:49+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2019-11-14 11:22+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 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 "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 "" "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 "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 "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 "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 "" "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 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, TCP or UDP." msgstr "" "The protocol for which this pool and its members listen. A valid value is " "HTTP, HTTPS, PROXY, TCP or UDP." 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 1 and 256." msgstr "The weight must be a number between 1 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 higher weight means it will receive " "more traffic. Must be\n" " a number from 1 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 higher weight means it will receive " "more traffic. Must be\n" " a number from 1 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 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." ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/fr/0000755000175000017500000000000000000000000023577 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/fr/LC_MESSAGES/0000755000175000017500000000000000000000000025364 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/fr/LC_MESSAGES/django.po0000644000175000017500000001410200000000000027164 0ustar00coreycorey00000000000000# 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" ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/id/0000755000175000017500000000000000000000000023564 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/id/LC_MESSAGES/0000755000175000017500000000000000000000000025351 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/id/LC_MESSAGES/django.po0000644000175000017500000000113500000000000027153 0ustar00coreycorey00000000000000# 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" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/id/LC_MESSAGES/djangojs.po0000644000175000017500000012035600000000000027517 0ustar00coreycorey00000000000000# 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: 2019-08-26 15:40+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:55+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 protocol for which this pool and its members listen. A valid value is " "HTTP, HTTPS, PROXY, TCP or UDP." msgstr "" "Protokol tempat pool ini dan listen anggotanya. Nilai yang valid adalah " "HTTP, HTTPS, PROXY, TCP atau UDP." 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 "The weight must be a number between 1 and 256." msgstr "Bobot harus berupa angka antara 1 dan 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 higher weight means it will receive " "more traffic. Must be\n" " a number from 1 to 256." msgstr "" "Bobot anggota menentukan porsi permintaan atau koneksi yang layanannya " "dibandingkan\n" "   ke anggota pool lainnya. Bobot yang lebih tinggi berarti akan menerima " "lebih banyak lalu lintas. Harus\n" "   nomor dari 1 sampai 256." 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." ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ja/0000755000175000017500000000000000000000000023562 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ja/LC_MESSAGES/0000755000175000017500000000000000000000000025347 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ja/LC_MESSAGES/django.po0000644000175000017500000000114100000000000027146 0ustar00coreycorey00000000000000# 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 "ロードバランサー" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ja/LC_MESSAGES/djangojs.po0000644000175000017500000013321000000000000027506 0ustar00coreycorey00000000000000# 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: 2019-10-03 15:01+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-01 03:24+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 protocol for which this pool and its members listen. A valid value is " "HTTP, HTTPS, PROXY, TCP or UDP." msgstr "" "このプールおよびそのメンバーがリッスンする際のプロトコル。有効な値は HTTP、" "HTTPS、PROXY、TCP、または UDP です。" 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 "The weight must be a number between 1 and 256." msgstr "重みは 1 〜 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 higher weight means it will receive " "more traffic. Must be\n" " a number from 1 to 256." msgstr "" "メンバーの重みによって、そのメンバーが処理するリクエストまたは接続の割合 " "(プールの他のメンバーに対する割合) が決定されます。\n" " 重みが高いと、より多くのトラフィックを受信することになります。\n" " 1 から 256 までの数字でなければいけません。" 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\" を選択しました。削除されたプールは元に戻せません。" ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ko_KR/0000755000175000017500000000000000000000000024175 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ko_KR/LC_MESSAGES/0000755000175000017500000000000000000000000025762 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ko_KR/LC_MESSAGES/django.po0000644000175000017500000000114600000000000027566 0ustar00coreycorey00000000000000# 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 "로드 밸런서" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ko_KR/LC_MESSAGES/djangojs.po0000644000175000017500000012376700000000000030141 0ustar00coreycorey00000000000000# 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 msgid "" msgstr "" "Project-Id-Version: octavia-dashboard VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2019-09-24 10:58+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:04+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" #, 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 "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 protocol for which this pool and its members listen. A valid value is " "HTTP, HTTPS, PROXY, TCP or UDP." msgstr "" "풀 및 풀 구성원이 리스닝하는 프로토콜. 유효한 값은 HTTP, HTTPS, PROXY, TCP 또" "는 UDP가 있습니다." 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 "The weight must be a number between 1 and 256." msgstr "가중치는 반드시 숫자 1과 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 higher weight means it will receive " "more traffic. Must be\n" " a number from 1 to 256." msgstr "" "멤버의 가중치는 풀의 다른 멤버와 비교하여 요청이나 연결의\n" " 양을 결정합니다. 가중치가 높을수록 더 많은 트래픽을 받게 됩니다.\n" " 가중치는 숫자 1과 256사이여야 합니다." 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 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\"를 선택했습니다. 삭제된 풀은 복구되지 않습니다." ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/pt_BR/0000755000175000017500000000000000000000000024176 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/pt_BR/LC_MESSAGES/0000755000175000017500000000000000000000000025763 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/pt_BR/LC_MESSAGES/django.po0000644000175000017500000000121600000000000027565 0ustar00coreycorey00000000000000# 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" ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ru/0000755000175000017500000000000000000000000023616 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ru/LC_MESSAGES/0000755000175000017500000000000000000000000025403 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ru/LC_MESSAGES/django.po0000644000175000017500000002051000000000000027203 0ustar00coreycorey00000000000000# 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 "балансировщик нагрузки" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/ru/LC_MESSAGES/djangojs.po0000644000175000017500000007017000000000000027547 0ustar00coreycorey00000000000000# 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\". Пожалуйста подтвердите ваш выбор. Удаление пулов " "необратимо." ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/zh_CN/0000755000175000017500000000000000000000000024171 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/zh_CN/LC_MESSAGES/0000755000175000017500000000000000000000000025756 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/zh_CN/LC_MESSAGES/django.po0000644000175000017500000000113200000000000027555 0ustar00coreycorey00000000000000# 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: 2018-08-15 05: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-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 "负载均衡器" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/zh_CN/LC_MESSAGES/djangojs.po0000644000175000017500000011327500000000000030126 0ustar00coreycorey00000000000000# 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: 2019-09-23 06:48+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-23 02:34+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 protocol for which this pool and its members listen. A valid value is " "HTTP, HTTPS, PROXY, TCP or UDP." msgstr "该资源池及其成员监听的协议。有效值为 HTTP,HTTPS,PROXY,TCP 或 UDP。" 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 "The weight must be a number between 1 and 256." msgstr "权重必须是 1 至 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 higher weight means it will receive " "more traffic. Must be\n" " a number from 1 to 256." msgstr "" "成员的权重决定了它在服务中与其他池成员的请求和连接的占比。\n" "权重越高意味着接收的消息越多。\n" "必须是 1 至 256 之间的整数。" 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”。删除的资源池无法恢复。" ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/zh_TW/0000755000175000017500000000000000000000000024223 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/zh_TW/LC_MESSAGES/0000755000175000017500000000000000000000000026010 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/zh_TW/LC_MESSAGES/django.po0000644000175000017500000000115200000000000027611 0ustar00coreycorey00000000000000# 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: 2018-08-15 05: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-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 "負載均衡器" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/locale/zh_TW/LC_MESSAGES/djangojs.po0000644000175000017500000010710400000000000030152 0ustar00coreycorey00000000000000# 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: 2019-08-26 15:40+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 "The weight must be a number between 1 and 256." msgstr "權重必須是 1 至 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 higher weight means it will receive " "more traffic. Must be\n" " a number from 1 to 256." msgstr "" "成員的權重決定了它在服務中與其他池成員的請求和連接的占比。\n" "權重越高意味着接收的消息越多。\n" "必須是 1 至 256 之間的整數。" 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”。刪除的資源池無法恢復。" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/post_install.sh0000755000175000017500000000067400000000000025012 0ustar00coreycorey00000000000000#!/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; ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/0000755000175000017500000000000000000000000023220 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/0000755000175000017500000000000000000000000024000 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/0000755000175000017500000000000000000000000024730 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/openstack-service-api/0000755000175000017500000000000000000000000031124 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021100000000000011447 xustar0000000000000000115 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/openstack-service-api/barbican.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/openstack-service-api/barbican.servi0000644000175000017500000000500400000000000033736 0ustar00coreycorey00000000000000/* * 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.barbican', barbicanAPI); barbicanAPI.$inject = [ 'horizon.framework.util.http.service', 'horizon.framework.widgets.toast.service' ]; /** * @ngdoc service * @name horizon.app.core.openstack-service-api.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 barbican service API. */ function barbicanAPI(apiService, toastService) { var service = { getCertificates: getCertificates, getSecrets: getSecrets }; return service; /////////////// // SSL Certificate Containers /** * @name horizon.app.core.openstack-service-api.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/barbican/certificates/'); return quiet ? promise : promise.error(function handleError() { toastService.add('error', gettext('Unable to retrieve SSL certificates.')); }); } // Secrets /** * @name horizon.app.core.openstack-service-api.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/barbican/secrets/'); return quiet ? promise : promise.error(function handleError() { toastService.add('error', gettext('Unable to retrieve secrets.')); }); } } }()); ././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000120 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/openstack-service-api/barbican.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/openstack-service-api/barbican.servi0000644000175000017500000000436300000000000033745 0ustar00coreycorey00000000000000/* * 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.barbican', function(barbicanAPI) { service = barbicanAPI; }])); it('defines the service', function() { expect(service).toBeDefined(); }); var tests = [ { func: "getCertificates", method: "get", path: "/api/barbican/certificates/", error: "Unable to retrieve SSL certificates." }, { func: "getSecrets", method: "get", path: "/api/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"); }); }); })(); ././@PaxHeader0000000000000000000000000000021000000000000011446 xustar0000000000000000114 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.servic0000644000175000017500000007221000000000000033675 0ustar00coreycorey00000000000000/* * 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 }) .error(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 }) .error(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.error(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) .error(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) .error(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) .error(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) .error(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) .error(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) .error(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.error(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) .error(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) .error(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) .error(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) .error(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.error(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) .error(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) .error(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) .error(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) .error(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.error(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/') .error(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 + '/') .error(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) .error(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) .error(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.error(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/') .error(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 + '/') .error(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 + '/') .error(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) .error(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) .error(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) .error(function () { toastService.add('error', gettext('Unable to retrieve health monitors.')); }); } function getHealthMonitor(monitorId) { return apiService.get('/api/lbaas/healthmonitors/' + monitorId + '/') .error(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) .error(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.error(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) .error(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) .error(function () { toastService.add('error', gettext('Unable to retrieve flavors.')); }); } function getFlavor(flavorId) { return apiService.get('/api/lbaas/flavors/' + flavorId + '/') .error(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) .error(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.error(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) .error(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) .error(function () { toastService.add('error', gettext('Unable to retrieve flavor profiles.')); }); } function getFlavorProfile(flavorProfileId) { return apiService.get('/api/lbaas/flavorprofiles/' + flavorProfileId + '/') .error(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) .error(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.error(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) .error(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) .error(function () { toastService.add('error', gettext('Unable to retrieve availability zones.')); }); } } }()); ././@PaxHeader0000000000000000000000000000021500000000000011453 xustar0000000000000000119 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/app/core/openstack-service-api/lbaasv2.servic0000644000175000017500000003667200000000000033711 0ustar00coreycorey00000000000000/* * 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"); }); }); })(); ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/0000755000175000017500000000000000000000000025147 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.000016 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/0000755000175000017500000000000000000000000026615 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/0000755000175000017500000000000000000000000030147 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/0000755000175000017500000000000000000000000033207 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000114 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/ 28 mtime=1586806716.0040157 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000755000175000017500000000000000000000000034050 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022500000000000011454 xustar0000000000000000121 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/ 28 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000755000175000017500000000000000000000000034050 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024700000000000011460 xustar0000000000000000145 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/create.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000000447400000000000034063 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000025400000000000011456 xustar0000000000000000150 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/create.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000000306600000000000034057 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000024300000000000011454 xustar0000000000000000141 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000000301700000000000034053 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000025000000000000011452 xustar0000000000000000146 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/create/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000000362000000000000034053 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000022500000000000011454 xustar0000000000000000121 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/delete/ 28 mtime=1586806716.0200145 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000755000175000017500000000000000000000000034050 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024700000000000011460 xustar0000000000000000145 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/delete/delete.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000001121700000000000034054 0ustar00coreycorey00000000000000/* * 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); } } })(); ././@PaxHeader0000000000000000000000000000025400000000000011456 xustar0000000000000000150 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/delete/delete.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000001133200000000000034052 0ustar00coreycorey00000000000000/* * 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 })(); ././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000119 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/ 28 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000755000175000017500000000000000000000000034050 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024300000000000011454 xustar0000000000000000141 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000000443400000000000034057 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000025000000000000011452 xustar0000000000000000146 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/edit.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000000310500000000000034051 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000024100000000000011452 xustar0000000000000000139 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000000257200000000000034060 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000024600000000000011457 xustar0000000000000000144 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/actions/edit/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/acti0000644000175000017500000000362500000000000034060 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000114 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/ 28 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000755000175000017500000000000000000000000034045 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023400000000000011454 xustar0000000000000000134 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/detail.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000644000175000017500000001167200000000000034056 0ustar00coreycorey00000000000000/* * 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); } } } })(); ././@PaxHeader0000000000000000000000000000024100000000000011452 xustar0000000000000000139 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/detail.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000644000175000017500000001241200000000000034047 0ustar00coreycorey00000000000000/* * 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); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000125 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/detail.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000644000175000017500000000542500000000000034055 0ustar00coreycorey00000000000000
././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000125 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/details/drawer.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/deta0000644000175000017500000000052100000000000034045 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000023000000000000011450 xustar0000000000000000130 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/healthmonitors.module.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/heal0000644000175000017500000001145300000000000034047 0ustar00coreycorey00000000000000/* * 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') }; } })(); ././@PaxHeader0000000000000000000000000000023500000000000011455 xustar0000000000000000135 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/healthmonitors.module.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/healthmonitors/heal0000644000175000017500000000433600000000000034051 0ustar00coreycorey00000000000000/* * 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) { if (action.id === value) { return true; } } } }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/0000755000175000017500000000000000000000000032221 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0040157 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000755000175000017500000000000000000000000033661 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022100000000000011450 xustar0000000000000000117 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/ 28 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000755000175000017500000000000000000000000033661 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024300000000000011454 xustar0000000000000000141 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000000445300000000000033671 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000025000000000000011452 xustar0000000000000000146 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/create.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000000367400000000000033675 0ustar00coreycorey00000000000000/* * 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); }); } }); })(); ././@PaxHeader0000000000000000000000000000023700000000000011457 xustar0000000000000000137 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000000276700000000000033677 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000024400000000000011455 xustar0000000000000000142 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/create/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000000360300000000000033665 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000022100000000000011450 xustar0000000000000000117 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/ 28 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000755000175000017500000000000000000000000033661 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024300000000000011454 xustar0000000000000000141 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000001045000000000000033663 0ustar00coreycorey00000000000000/* * 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); } } })(); ././@PaxHeader0000000000000000000000000000025000000000000011452 xustar0000000000000000146 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/delete/delete.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000000746100000000000033673 0ustar00coreycorey00000000000000/* * 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 })(); ././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000115 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/ 28 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000755000175000017500000000000000000000000033661 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023700000000000011457 xustar0000000000000000137 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000000431700000000000033670 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000024400000000000011455 xustar0000000000000000142 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/edit.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000000331600000000000033666 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000023500000000000011455 xustar0000000000000000135 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000000400000000000000033655 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000024200000000000011453 xustar0000000000000000140 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/edit/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/actions/0000644000175000017500000000505000000000000033663 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000755000175000017500000000000000000000000033646 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023000000000000011450 xustar0000000000000000130 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000644000175000017500000001154400000000000033655 0ustar00coreycorey00000000000000/* * 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); } } } })(); ././@PaxHeader0000000000000000000000000000023500000000000011455 xustar0000000000000000135 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000644000175000017500000001113200000000000033646 0ustar00coreycorey00000000000000/* * 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); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000121 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/detail.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000644000175000017500000000516200000000000033654 0ustar00coreycorey00000000000000
././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000121 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/drawer.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/details/0000644000175000017500000000046200000000000033652 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000022000000000000011447 xustar0000000000000000122 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7polici0000644000175000017500000001132700000000000033672 0ustar00coreycorey00000000000000/* * 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') }; } })(); ././@PaxHeader0000000000000000000000000000022500000000000011454 xustar0000000000000000127 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7policies.module.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7policies/l7polici0000644000175000017500000000423600000000000033673 0ustar00coreycorey00000000000000/* * 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) { if (action.id === value) { return true; } } } }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/0000755000175000017500000000000000000000000031544 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0040157 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/0000755000175000017500000000000000000000000033204 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000114 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/ 28 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000755000175000017500000000000000000000000033676 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024000000000000011451 xustar0000000000000000138 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000644000175000017500000000442500000000000033705 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000024500000000000011456 xustar0000000000000000143 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/create.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000644000175000017500000000366500000000000033712 0ustar00coreycorey00000000000000/* * 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); }); } }); })(); ././@PaxHeader0000000000000000000000000000023400000000000011454 xustar0000000000000000134 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000644000175000017500000000274600000000000033711 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000024100000000000011452 xustar0000000000000000139 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/create/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/cre0000644000175000017500000000357700000000000033714 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000114 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/ 28 mtime=1586806716.0240142 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/del0000755000175000017500000000000000000000000033671 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024000000000000011451 xustar0000000000000000138 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/del0000644000175000017500000001051000000000000033670 0ustar00coreycorey00000000000000/* * 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); } } })(); ././@PaxHeader0000000000000000000000000000024500000000000011456 xustar0000000000000000143 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/delete/delete.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/del0000644000175000017500000000752000000000000033677 0ustar00coreycorey00000000000000/* * 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 })(); ././@PaxHeader0000000000000000000000000000021300000000000011451 xustar0000000000000000112 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/ 27 mtime=1586806716.028014 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000755000175000017500000000000000000000000033666 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023400000000000011454 xustar0000000000000000134 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000644000175000017500000000426500000000000033677 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000024100000000000011452 xustar0000000000000000139 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/edit.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000644000175000017500000000330300000000000033667 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000023200000000000011452 xustar0000000000000000132 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000644000175000017500000000375600000000000033703 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000023700000000000011457 xustar0000000000000000137 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edit/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/actions/edi0000644000175000017500000000503000000000000033666 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.028014 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/0000755000175000017500000000000000000000000033171 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022500000000000011454 xustar0000000000000000127 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/det0000644000175000017500000001174700000000000033702 0ustar00coreycorey00000000000000/* * 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); } } } })(); ././@PaxHeader0000000000000000000000000000023200000000000011452 xustar0000000000000000132 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/det0000644000175000017500000001123400000000000033671 0ustar00coreycorey00000000000000/* * 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); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021400000000000011452 xustar0000000000000000118 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/detail.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/details/det0000644000175000017500000000460100000000000033671 0ustar00coreycorey00000000000000
././@PaxHeader0000000000000000000000000000021200000000000011450 xustar0000000000000000116 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.mod0000644000175000017500000001120400000000000033640 0ustar00coreycorey00000000000000/* * 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'] } }; } })(); ././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000121 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.module.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/l7rules/l7rules.mod0000644000175000017500000000421200000000000033641 0ustar00coreycorey00000000000000/* * 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) { if (action.id === value) { return true; } } } }); })(); ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.js0000644000175000017500000005033700000000000033333 0ustar00coreycorey00000000000000/* * 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' }); } }()); ././@PaxHeader0000000000000000000000000000020700000000000011454 xustar0000000000000000113 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.module.spec0000644000175000017500000005035100000000000033645 0ustar00coreycorey00000000000000/* * 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'); }) ); }); })(); ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/lbaasv2.scss0000644000175000017500000000573600000000000032411 0ustar00coreycorey00000000000000/* * 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; } } } } ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.028014 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/0000755000175000017500000000000000000000000032157 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0040157 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/0000755000175000017500000000000000000000000033617 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000116 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/ 27 mtime=1586806716.028014 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000755000175000017500000000000000000000000033762 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023300000000000011453 xustar0000000000000000133 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/create.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000644000175000017500000000431100000000000033763 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000024000000000000011451 xustar0000000000000000138 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/create.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000644000175000017500000000347600000000000033776 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000023600000000000011456 xustar0000000000000000136 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000644000175000017500000000275200000000000033772 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000024300000000000011454 xustar0000000000000000141 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/create/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/c0000644000175000017500000000353500000000000033772 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000116 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/delete/ 27 mtime=1586806716.028014 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/d0000755000175000017500000000000000000000000033763 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024200000000000011453 xustar0000000000000000140 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/delete/delete.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/d0000644000175000017500000001015500000000000033767 0ustar00coreycorey00000000000000/* * 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); } } })(); ././@PaxHeader0000000000000000000000000000024700000000000011460 xustar0000000000000000145 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/delete/delete.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/d0000644000175000017500000001234400000000000033771 0ustar00coreycorey00000000000000/* * 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.'); }); }); })(); ././@PaxHeader0000000000000000000000000000021500000000000011453 xustar0000000000000000114 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/ 27 mtime=1586806716.028014 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000755000175000017500000000000000000000000033764 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022700000000000011456 xustar0000000000000000129 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/edit.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000644000175000017500000000432300000000000033770 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000023400000000000011454 xustar0000000000000000134 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/edit.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000644000175000017500000000351600000000000033773 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000023400000000000011454 xustar0000000000000000134 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000644000175000017500000000371000000000000033767 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000024100000000000011452 xustar0000000000000000139 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/edit/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/actions/e0000644000175000017500000000511100000000000033764 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.028014 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/0000755000175000017500000000000000000000000033604 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022700000000000011456 xustar0000000000000000129 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/d0000644000175000017500000001100400000000000033746 0ustar00coreycorey00000000000000/* * 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); } } } })(); ././@PaxHeader0000000000000000000000000000023400000000000011454 xustar0000000000000000134 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/d0000644000175000017500000001105200000000000033751 0ustar00coreycorey00000000000000/* * 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); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000120 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/detail.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/d0000644000175000017500000000562500000000000033762 0ustar00coreycorey00000000000000
././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000120 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/drawer.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/details/d0000644000175000017500000000065100000000000033754 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000120 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners.module.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners0000644000175000017500000001231200000000000034111 0ustar00coreycorey00000000000000/* * 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 ] }, 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') }; } })(); ././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000125 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners.module.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/listeners/listeners0000644000175000017500000000426600000000000034122 0ustar00coreycorey00000000000000/* * 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) { if (action.id === value) { return true; } } } }); })(); ././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1586806716.028014 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/0000755000175000017500000000000000000000000032741 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021500000000000011453 xustar0000000000000000113 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/ 28 mtime=1586806716.0040157 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000755000175000017500000000000000000000000033761 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023200000000000011452 xustar0000000000000000126 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/ 28 mtime=1586806716.0320137 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000755000175000017500000000000000000000000033761 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024700000000000011460 xustar0000000000000000145 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000702700000000000033771 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000025400000000000011456 xustar0000000000000000150 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000001257600000000000033776 0ustar00coreycorey00000000000000/* * 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]; 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]; 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); }); }); })(); ././@PaxHeader0000000000000000000000000000023600000000000011456 xustar0000000000000000136 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000256000000000000033766 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000024400000000000011455 xustar0000000000000000142 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000717300000000000033773 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000025100000000000011453 xustar0000000000000000147 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/associate-ip/modal.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000001003200000000000033757 0ustar00coreycorey00000000000000/* * 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(); }); }); })(); ././@PaxHeader0000000000000000000000000000022400000000000011453 xustar0000000000000000120 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/ 28 mtime=1586806716.0320137 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000755000175000017500000000000000000000000033761 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023700000000000011457 xustar0000000000000000137 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/create.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000441100000000000033763 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000024400000000000011455 xustar0000000000000000142 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/create.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000356000000000000033767 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000024200000000000011453 xustar0000000000000000140 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000314500000000000033766 0ustar00coreycorey00000000000000/* * 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'); } })(); ././@PaxHeader0000000000000000000000000000024700000000000011460 xustar0000000000000000145 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/create/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000346400000000000033772 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000022400000000000011453 xustar0000000000000000120 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/delete/ 28 mtime=1586806716.0320137 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000755000175000017500000000000000000000000033761 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024600000000000011457 xustar0000000000000000144 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/delete/delete.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000001251500000000000033767 0ustar00coreycorey00000000000000/* * 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); } } 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; } } })(); ././@PaxHeader0000000000000000000000000000025300000000000011455 xustar0000000000000000149 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/delete/delete.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000001273400000000000033772 0ustar00coreycorey00000000000000/* * 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.'); }); }); })(); ././@PaxHeader0000000000000000000000000000023500000000000011455 xustar0000000000000000129 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/disassociate-ip/ 28 mtime=1586806716.0320137 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000755000175000017500000000000000000000000033761 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024700000000000011460 xustar0000000000000000145 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/disassociate-ip/modal.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000655500000000000033776 0ustar00coreycorey00000000000000/* * 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(); } } })(); ././@PaxHeader0000000000000000000000000000025400000000000011456 xustar0000000000000000150 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/disassociate-ip/modal.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000775600000000000034002 0ustar00coreycorey00000000000000/* * 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(); }); }); })(); ././@PaxHeader0000000000000000000000000000022200000000000011451 xustar0000000000000000118 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/ 28 mtime=1586806716.0320137 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000755000175000017500000000000000000000000033761 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023300000000000011453 xustar0000000000000000133 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/edit.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000463000000000000033766 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000024000000000000011451 xustar0000000000000000138 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/edit.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000403700000000000033767 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000024000000000000011451 xustar0000000000000000138 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000314500000000000033766 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000024500000000000011456 xustar0000000000000000143 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actions/edit/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/actio0000644000175000017500000000416000000000000033764 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000021500000000000011453 xustar0000000000000000113 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/ 28 mtime=1586806716.0320137 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000755000175000017500000000000000000000000033750 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023300000000000011453 xustar0000000000000000133 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/detail.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000644000175000017500000001077300000000000033762 0ustar00coreycorey00000000000000/* * 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); } } } })(); ././@PaxHeader0000000000000000000000000000024000000000000011451 xustar0000000000000000138 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/detail.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000644000175000017500000001101500000000000033750 0ustar00coreycorey00000000000000/* * 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); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022200000000000011451 xustar0000000000000000124 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/detail.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000644000175000017500000000536700000000000033765 0ustar00coreycorey00000000000000
././@PaxHeader0000000000000000000000000000022200000000000011451 xustar0000000000000000124 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/details/drawer.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/detai0000644000175000017500000000051700000000000033755 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000022600000000000011455 xustar0000000000000000128 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.module.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadb0000644000175000017500000001306600000000000033753 0ustar00coreycorey00000000000000/* * 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'] } }; } })(); ././@PaxHeader0000000000000000000000000000023300000000000011453 xustar0000000000000000133 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.module.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadb0000644000175000017500000000457700000000000033762 0ustar00coreycorey00000000000000/* * 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) { if (action.id === value) { return true; } } } }); })(); ././@PaxHeader0000000000000000000000000000022700000000000011456 xustar0000000000000000129 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadb0000644000175000017500000002557400000000000033762 0ustar00coreycorey00000000000000/* * 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'), 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(); } }); } } }()); ././@PaxHeader0000000000000000000000000000023400000000000011454 xustar0000000000000000134 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadbalancers.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/loadb0000644000175000017500000003062000000000000033746 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000022200000000000011451 xustar0000000000000000124 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel0000644000175000017500000000414100000000000033763 0ustar00coreycorey00000000000000/* * 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); } ); } })(); ././@PaxHeader0000000000000000000000000000022700000000000011456 xustar0000000000000000129 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel0000644000175000017500000000372300000000000033770 0ustar00coreycorey00000000000000/* * 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(); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021100000000000011447 xustar0000000000000000115 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/loadbalancers/panel0000644000175000017500000000104000000000000033756 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0320137 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/0000755000175000017500000000000000000000000031601 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0040157 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/0000755000175000017500000000000000000000000033241 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000114 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/delete/ 28 mtime=1586806716.0320137 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/del0000755000175000017500000000000000000000000033726 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024000000000000011451 xustar0000000000000000138 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/delete/delete.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/del0000644000175000017500000001071200000000000033731 0ustar00coreycorey00000000000000/* * 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); } } })(); ././@PaxHeader0000000000000000000000000000024500000000000011456 xustar0000000000000000143 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/delete/delete.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/del0000644000175000017500000001121400000000000033727 0ustar00coreycorey00000000000000/* * 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 })(); ././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000119 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/ 28 mtime=1586806716.0320137 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000755000175000017500000000000000000000000033723 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024000000000000011451 xustar0000000000000000138 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000644000175000017500000000627700000000000033741 0ustar00coreycorey00000000000000/* * 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 1 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; } } })(); ././@PaxHeader0000000000000000000000000000024500000000000011456 xustar0000000000000000143 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000644000175000017500000000732700000000000033736 0ustar00coreycorey00000000000000/* * 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 1 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() { 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); }); }); })(); ././@PaxHeader0000000000000000000000000000022700000000000011456 xustar0000000000000000129 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000644000175000017500000001273600000000000033736 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000023500000000000011455 xustar0000000000000000135 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000644000175000017500000000652600000000000033736 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000024200000000000011453 xustar0000000000000000140 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edit-member/modal.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/edi0000644000175000017500000000651400000000000033733 0ustar00coreycorey00000000000000/* * 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.'); }); }); })(); ././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000119 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/ 28 mtime=1586806716.0360134 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000755000175000017500000000000000000000000033752 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000025200000000000011454 xustar0000000000000000148 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/update-member-list.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000644000175000017500000000447000000000000033761 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000025700000000000011461 xustar0000000000000000153 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/update-member-list.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000644000175000017500000000356300000000000033763 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000024100000000000011452 xustar0000000000000000139 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000644000175000017500000000275600000000000033766 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000024600000000000011457 xustar0000000000000000144 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/update-list/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/actions/upd0000644000175000017500000000450000000000000033753 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0360134 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/0000755000175000017500000000000000000000000033226 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022500000000000011454 xustar0000000000000000127 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/detail.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/det0000644000175000017500000001161300000000000033727 0ustar00coreycorey00000000000000/* * 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); } } } })(); ././@PaxHeader0000000000000000000000000000023200000000000011452 xustar0000000000000000132 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/detail.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/det0000644000175000017500000001227300000000000033732 0ustar00coreycorey00000000000000/* * 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); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021400000000000011452 xustar0000000000000000118 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/detail.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/det0000644000175000017500000000554700000000000033740 0ustar00coreycorey00000000000000
././@PaxHeader0000000000000000000000000000021400000000000011452 xustar0000000000000000118 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/drawer.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/details/dra0000644000175000017500000000045600000000000033724 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000021200000000000011450 xustar0000000000000000116 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/members.module.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/members.mod0000644000175000017500000001136200000000000033737 0ustar00coreycorey00000000000000/* * 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'] } }; } })(); ././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000121 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/members.module.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/members/members.mod0000644000175000017500000000424600000000000033742 0ustar00coreycorey00000000000000/* * 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) { if (action.id === value) { return true; } } } }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0360134 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/0000755000175000017500000000000000000000000031303 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0040157 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/0000755000175000017500000000000000000000000032743 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021400000000000011452 xustar0000000000000000112 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/ 28 mtime=1586806716.0360134 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000755000175000017500000000000000000000000033762 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023600000000000011456 xustar0000000000000000136 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000644000175000017500000000445400000000000033773 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000024300000000000011454 xustar0000000000000000141 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/create.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000644000175000017500000000371300000000000033770 0ustar00coreycorey00000000000000/* * 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); }); } }); })(); ././@PaxHeader0000000000000000000000000000023200000000000011452 xustar0000000000000000132 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000644000175000017500000000307500000000000033771 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000023700000000000011457 xustar0000000000000000137 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/create/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/creat0000644000175000017500000000412500000000000033766 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000021400000000000011452 xustar0000000000000000112 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delete/ 28 mtime=1586806716.0360134 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delet0000755000175000017500000000000000000000000033761 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023600000000000011456 xustar0000000000000000136 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delete/delete.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delet0000644000175000017500000001050700000000000033766 0ustar00coreycorey00000000000000/* * 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); } } })(); ././@PaxHeader0000000000000000000000000000024300000000000011454 xustar0000000000000000141 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delete/delete.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/delet0000644000175000017500000001115100000000000033762 0ustar00coreycorey00000000000000/* * 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 })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0360134 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000755000175000017500000000000000000000000033670 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023200000000000011452 xustar0000000000000000132 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/edit.action.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000644000175000017500000000427300000000000033700 0ustar00coreycorey00000000000000/* * 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; } } })(); ././@PaxHeader0000000000000000000000000000023700000000000011457 xustar0000000000000000137 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/edit.action.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000644000175000017500000000352200000000000033674 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000023000000000000011450 xustar0000000000000000130 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/wizard.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000644000175000017500000000364200000000000033677 0ustar00coreycorey00000000000000/* * 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); } })(); ././@PaxHeader0000000000000000000000000000023500000000000011455 xustar0000000000000000135 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/wizard.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/actions/edit/0000644000175000017500000000472700000000000033704 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0720108 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/0000755000175000017500000000000000000000000032730 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000125 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detail.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detai0000644000175000017500000001167600000000000033754 0ustar00coreycorey00000000000000/* * 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); } } } })(); ././@PaxHeader0000000000000000000000000000023000000000000011450 xustar0000000000000000130 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detail.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detai0000644000175000017500000001215300000000000033743 0ustar00coreycorey00000000000000/* * 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); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021200000000000011450 xustar0000000000000000116 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detail.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/detai0000644000175000017500000000577300000000000033755 0ustar00coreycorey00000000000000
././@PaxHeader0000000000000000000000000000021200000000000011450 xustar0000000000000000116 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/drawer.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/details/drawe0000644000175000017500000000045500000000000033761 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000020600000000000011453 xustar0000000000000000112 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.0000644000175000017500000001137100000000000033727 0ustar00coreycorey00000000000000/* * 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') }; } })(); ././@PaxHeader0000000000000000000000000000021300000000000011451 xustar0000000000000000117 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/pools/pools.module.0000644000175000017500000000422600000000000033730 0ustar00coreycorey00000000000000/* * 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) { if (action.id === value) { return true; } } } }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0040157 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/util/0000755000175000017500000000000000000000000031124 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0720108 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/0000755000175000017500000000000000000000000033274 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000125 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/validate-unique.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/val0000644000175000017500000000377100000000000034011 0ustar00coreycorey00000000000000/* * 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; } } } })(); ././@PaxHeader0000000000000000000000000000023000000000000011450 xustar0000000000000000130 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/validate-unique.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/util/validators/val0000644000175000017500000000431400000000000034003 0ustar00coreycorey00000000000000/* * 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); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0040157 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/0000755000175000017500000000000000000000000031615 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021400000000000011452 xustar0000000000000000112 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/ 28 mtime=1586806716.0720108 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselec0000755000175000017500000000000000000000000034037 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024000000000000011451 xustar0000000000000000138 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/filter-select.component.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselec0000644000175000017500000001740500000000000034050 0ustar00coreycorey00000000000000/* * 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 = []; // 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.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.rows.length = 0; angular.forEach(ctrl.options, function(option) { var row = ctrl._buildRow(option); if (row) { ctrl.rows.push(row); } }); }; 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'; } })(); ././@PaxHeader0000000000000000000000000000024500000000000011456 xustar0000000000000000143 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/filter-select.component.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselec0000644000175000017500000002213100000000000034040 0ustar00coreycorey00000000000000/* * 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); }); }); describe('controller', function() { var scope, ctrl; beforeEach(module('horizon.dashboard.project.lbaasv2')); beforeEach( inject( function($rootScope, $componentController) { 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 }); }); }); }); })(); ././@PaxHeader0000000000000000000000000000023000000000000011450 xustar0000000000000000130 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselect/filter-select.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/filterselec0000644000175000017500000000310300000000000034036 0ustar00coreycorey00000000000000
{$ column.label $}
{$ column[0] $}{$ column[1] $}{$ column[2] $}
No matching options
././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0720108 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/0000755000175000017500000000000000000000000032704 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023000000000000011450 xustar0000000000000000130 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table-status.directive.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table0000644000175000017500000000312700000000000033721 0ustar00coreycorey00000000000000/* * 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; } }()); ././@PaxHeader0000000000000000000000000000023500000000000011455 xustar0000000000000000135 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table-status.directive.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table0000644000175000017500000000712700000000000033725 0ustar00coreycorey00000000000000/* * 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); }); }); }()); ././@PaxHeader0000000000000000000000000000022000000000000011447 xustar0000000000000000122 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table-status.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/widgets/table/table0000644000175000017500000000123400000000000033716 0ustar00coreycorey00000000000000 No items to display.
Loading An error occurred. Please try again later.
././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0760105 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/0000755000175000017500000000000000000000000032021 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021500000000000011453 xustar0000000000000000113 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/ 28 mtime=1586806716.0760105 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000755000175000017500000000000000000000000034057 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024100000000000011452 xustar0000000000000000139 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000644000175000017500000000333500000000000034065 0ustar00coreycorey00000000000000/* * 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') }; } })(); ././@PaxHeader0000000000000000000000000000024600000000000011457 xustar0000000000000000144 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000644000175000017500000000372300000000000034066 0ustar00coreycorey00000000000000/* * 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); }); }); }); })(); ././@PaxHeader0000000000000000000000000000023500000000000011455 xustar0000000000000000135 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.help.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000644000175000017500000000151400000000000034062 0ustar00coreycorey00000000000000

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:

././@PaxHeader0000000000000000000000000000023000000000000011450 xustar0000000000000000130 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificates/certificates.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/certificat0000644000175000017500000000623400000000000034066 0ustar00coreycorey00000000000000

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 $}
././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0760105 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/0000755000175000017500000000000000000000000033563 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023100000000000011451 xustar0000000000000000131 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l0000644000175000017500000000277400000000000033753 0ustar00coreycorey00000000000000/* * 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.'); } })(); ././@PaxHeader0000000000000000000000000000023600000000000011456 xustar0000000000000000136 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l0000644000175000017500000000221100000000000033735 0ustar00coreycorey00000000000000/* * 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(); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022500000000000011454 xustar0000000000000000127 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.help.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l0000644000175000017500000000235700000000000033750 0ustar00coreycorey00000000000000

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.

././@PaxHeader0000000000000000000000000000022000000000000011447 xustar0000000000000000122 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l7policy.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7policy/l0000644000175000017500000000753600000000000033754 0ustar00coreycorey00000000000000

Provide the details for the l7 policy.

{$ ::ctrl.redirectUrlError $}
{$ ::ctrl.positionError $}
././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0760105 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/0000755000175000017500000000000000000000000033233 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022100000000000011450 xustar0000000000000000123 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.help.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7r0000644000175000017500000000405600000000000033667 0ustar00coreycorey00000000000000

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.

././@PaxHeader0000000000000000000000000000021400000000000011452 xustar0000000000000000118 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7rule.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/l7rule/l7r0000644000175000017500000000720700000000000033670 0ustar00coreycorey00000000000000

Provide the details for the l7 rule.

././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0760105 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/0000755000175000017500000000000000000000000033646 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000023100000000000011451 xustar0000000000000000131 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/l0000644000175000017500000000510000000000000034020 0ustar00coreycorey00000000000000/* * 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; // 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.'); //////////// 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 listenerPortExists(port) { return $scope.model.listenerPorts.some(function(element) { return element === port; }); } } })(); ././@PaxHeader0000000000000000000000000000023600000000000011456 xustar0000000000000000136 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/l0000644000175000017500000000673700000000000034041 0ustar00coreycorey00000000000000/* * 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: { 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 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(); }); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022500000000000011454 xustar0000000000000000127 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.help.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/l0000644000175000017500000000357400000000000034035 0ustar00coreycorey00000000000000

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.

././@PaxHeader0000000000000000000000000000022000000000000011447 xustar0000000000000000122 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/listener.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/listener/l0000644000175000017500000002227400000000000034033 0ustar00coreycorey00000000000000

Provide the details for the listener.

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

Insert Headers

././@PaxHeader0000000000000000000000000000021500000000000011453 xustar0000000000000000113 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/ 28 mtime=1586806716.0800102 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000755000175000017500000000000000000000000034022 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000024100000000000011452 xustar0000000000000000139 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000644000175000017500000001414100000000000034025 0ustar00coreycorey00000000000000/* * 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.name; } 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]; }); }; } })(); ././@PaxHeader0000000000000000000000000000024600000000000011457 xustar0000000000000000144 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000644000175000017500000002421200000000000034025 0ustar00coreycorey00000000000000/* * 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].name); 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'); }); }); }); })(); ././@PaxHeader0000000000000000000000000000023500000000000011455 xustar0000000000000000135 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.help.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000644000175000017500000000107100000000000034023 0ustar00coreycorey00000000000000

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.

././@PaxHeader0000000000000000000000000000023000000000000011450 xustar0000000000000000130 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalancer/loadbalancer.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/loadbalanc0000644000175000017500000000777700000000000034046 0ustar00coreycorey00000000000000

Provide the details for the load balancer.

{$ ::ctrl.ipError $}
././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0800102 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/0000755000175000017500000000000000000000000033453 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022700000000000011456 xustar0000000000000000129 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/me0000644000175000017500000001104400000000000033777 0ustar00coreycorey00000000000000/* * 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 1 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; } } })(); ././@PaxHeader0000000000000000000000000000023400000000000011454 xustar0000000000000000134 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/me0000644000175000017500000001057200000000000034004 0ustar00coreycorey00000000000000/* * 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'); }); }); })(); ././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000125 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.help.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/me0000644000175000017500000000337600000000000034010 0ustar00coreycorey00000000000000

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 higher weight means it will receive more traffic. Must be a number from 1 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.

././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000120 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/members.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/members/me0000644000175000017500000003210100000000000033774 0ustar00coreycorey00000000000000

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
././@PaxHeader0000000000000000000000000000021200000000000011450 xustar0000000000000000116 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.serv0000644000175000017500000000635100000000000034023 0ustar00coreycorey00000000000000/* * 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); } } } } })(); ././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000121 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/modal.serv0000644000175000017500000000632400000000000034023 0ustar00coreycorey00000000000000/* * 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); }); }); }); })(); ././@PaxHeader0000000000000000000000000000021200000000000011450 xustar0000000000000000116 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.serv0000644000175000017500000007517700000000000034043 0ustar00coreycorey00000000000000/* * 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.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 barbicanAPI The 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, barbicanAPI, 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'], 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', 'TCP', 'UDP'], methods: ['LEAST_CONNECTIONS', 'ROUND_ROBIN', 'SOURCE_IP'], types: ['SOURCE_IP', 'HTTP_COOKIE', 'APP_COOKIE'], monitorTypes: ['HTTP', 'HTTPS', 'PING', 'TCP', 'TLS-HELLO', 'UDP-CONNECT'], 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 }; 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 }, 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 }, 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; } // 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; } 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 (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() { result.listener.sni_container_refs.forEach(function addAvailableCertificate(ref) { model.certificates.filter(function matchCertificate(cert) { return cert.id === ref; }).forEach(function addCertificate(cert) { model.spec.certificates.push(cert); }); }); }); $('#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; } 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; } 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([ barbicanAPI.getCertificates(true), barbicanAPI.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; } } })(); ././@PaxHeader0000000000000000000000000000021700000000000011455 xustar0000000000000000121 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/model.serv0000644000175000017500000027552500000000000034042 0ustar00coreycorey00000000000000/* * 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'}], sni_container_refs: ['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.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']); }); 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']); }); 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(5); 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(4); 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 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(14); 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(7); 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.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.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'); }); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0800102 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/0000755000175000017500000000000000000000000033510 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000022700000000000011456 xustar0000000000000000129 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.controller.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/mo0000644000175000017500000000521000000000000034044 0ustar00coreycorey00000000000000/* * 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"); } }); // 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; } })(); ././@PaxHeader0000000000000000000000000000023400000000000011454 xustar0000000000000000134 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.controller.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/mo0000644000175000017500000000425000000000000034047 0ustar00coreycorey00000000000000/* * 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 }); }); }); }); })(); ././@PaxHeader0000000000000000000000000000022300000000000011452 xustar0000000000000000125 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.help.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/mo0000644000175000017500000000315600000000000034053 0ustar00coreycorey00000000000000

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.

././@PaxHeader0000000000000000000000000000021600000000000011454 xustar0000000000000000120 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/monitor.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/monitor/mo0000644000175000017500000001465000000000000034054 0ustar00coreycorey00000000000000

Provide the details for the health monitor.

{$ ::ctrl.retryDownError $}
{$ ::ctrl.intervalError $}
{$ ::ctrl.retryError $}
{$ ::ctrl.timeoutError $}
{$ ::ctrl.statusError $}
{$ ::ctrl.pathError $}
././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0800102 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/0000755000175000017500000000000000000000000032772 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000021500000000000011453 xustar0000000000000000119 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.help.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.0000644000175000017500000000241100000000000033742 0ustar00coreycorey00000000000000

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, TCP or UDP.

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.

././@PaxHeader0000000000000000000000000000021000000000000011446 xustar0000000000000000114 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.html 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/pool/pool.0000644000175000017500000000700500000000000033746 0ustar00coreycorey00000000000000

Provide the details for the pool.

././@PaxHeader0000000000000000000000000000021500000000000011453 xustar0000000000000000119 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.s0000644000175000017500000001074400000000000034065 0ustar00coreycorey00000000000000/* * 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 }); } } })(); ././@PaxHeader0000000000000000000000000000022200000000000011451 xustar0000000000000000124 path=octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.service.spec.js 22 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/static/dashboard/project/lbaasv2/workflow/workflow.s0000644000175000017500000000716100000000000034064 0ustar00coreycorey00000000000000/* * 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(); }); }); })(); ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0800102 octavia-dashboard-4.1.0.dev21/octavia_dashboard/tests/0000755000175000017500000000000000000000000023073 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/tests/__init__.py0000644000175000017500000000000000000000000025172 0ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/tests/settings.py0000644000175000017500000000255300000000000025312 0ustar00coreycorey00000000000000# 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)) ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0800102 octavia-dashboard-4.1.0.dev21/octavia_dashboard/tests/unit/0000755000175000017500000000000000000000000024052 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/tests/unit/__init__.py0000644000175000017500000000000000000000000026151 0ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/tests/unit/registration.py0000644000175000017500000000174400000000000027144 0ustar00coreycorey00000000000000# 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) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/tests/urls.py0000644000175000017500000000140200000000000024427 0ustar00coreycorey00000000000000# 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.conf.urls import url import openstack_dashboard.urls urlpatterns = [ url(r'', include(openstack_dashboard.urls)) ] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard/version.py0000644000175000017500000000171000000000000023767 0ustar00coreycorey00000000000000# 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() ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0160148 octavia-dashboard-4.1.0.dev21/octavia_dashboard.egg-info/0000755000175000017500000000000000000000000023423 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806715.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard.egg-info/PKG-INFO0000644000175000017500000000724600000000000024531 0ustar00coreycorey00000000000000Metadata-Version: 1.1 Name: octavia-dashboard Version: 4.1.0.dev21 Summary: Horizon panels for Octavia Home-page: https://docs.openstack.org/octavia-dashboard/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: ================= 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 Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806715.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard.egg-info/SOURCES.txt0000644000175000017500000005103400000000000025312 0ustar00coreycorey00000000000000.coveragerc .eslintrc .mailmap .stestr.conf AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE README.rst babel-django.cfg babel-djangojs.cfg lower-constraints.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/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_AU/LC_MESSAGES/djangojs.po octavia_dashboard/locale/en_GB/LC_MESSAGES/django.po octavia_dashboard/locale/en_GB/LC_MESSAGES/djangojs.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_CN/LC_MESSAGES/django.po octavia_dashboard/locale/zh_CN/LC_MESSAGES/djangojs.po octavia_dashboard/locale/zh_TW/LC_MESSAGES/django.po octavia_dashboard/locale/zh_TW/LC_MESSAGES/djangojs.po octavia_dashboard/static/app/core/openstack-service-api/barbican.service.js octavia_dashboard/static/app/core/openstack-service-api/barbican.service.spec.js 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/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.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-RBAC-43ee180e712294ed.yaml releasenotes/notes/add-az-support-efdd4e7c5dccef21.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-timeout-options-8988fc477fa46d31.yaml releasenotes/notes/add-udp-support-acb1a22fb605d3a8.yaml releasenotes/notes/add-x-forwarded-proto-e30b52a3f853ed62.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-url-barbican-client-d41b03419fb31ba4.yaml releasenotes/notes/fix-flavor-no-flavor-profile-c3e82325f16d5ab8.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/pool-selection-hint-7f282ba1fa014d8c.yaml 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/_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././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806715.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard.egg-info/dependency_links.txt0000644000175000017500000000000100000000000027471 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806715.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard.egg-info/not-zip-safe0000644000175000017500000000000100000000000025651 0ustar00coreycorey00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806715.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard.egg-info/pbr.json0000644000175000017500000000005700000000000025103 0ustar00coreycorey00000000000000{"git_version": "761408e", "is_release": false}././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806715.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard.egg-info/requires.txt0000644000175000017500000000023100000000000026017 0ustar00coreycorey00000000000000Babel!=2.4.0,>=2.3.4 horizon>=17.1.0 openstacksdk>=0.24.0 oslo.log>=3.36.0 pbr!=2.1.0,>=2.0.0 python-barbicanclient>=4.5.2 python-keystoneclient>=3.22.0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806715.0 octavia-dashboard-4.1.0.dev21/octavia_dashboard.egg-info/top_level.txt0000644000175000017500000000002200000000000026147 0ustar00coreycorey00000000000000octavia_dashboard ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/package-lock.json0000644000175000017500000047160000000000000021520 0ustar00coreycorey00000000000000{ "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 } } } ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/package.json0000644000175000017500000000222100000000000020557 0ustar00coreycorey00000000000000{ "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": "1.10.3", "eslint-config-openstack": "1.2.4", "eslint-plugin-angular": "1.0.1", "jasmine-core": "2.4.1", "karma": "1.1.2", "karma-chrome-launcher": "1.0.1", "karma-cli": "1.0.1", "karma-coverage": "1.1.1", "karma-jasmine": "1.0.2", "karma-ng-html2js-preprocessor": "1.0.0", "karma-phantomjs-launcher": "1.0.4", "karma-threshold-reporter": "0.1.15", "phantomjs-prebuilt": "2.1.14" }, "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": {} } ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0080154 octavia-dashboard-4.1.0.dev21/releasenotes/0000755000175000017500000000000000000000000020765 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/notes/0000755000175000017500000000000000000000000022115 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/add-RBAC-43ee180e712294ed.yaml0000644000175000017500000000132200000000000026372 0ustar00coreycorey00000000000000--- 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. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/add-az-support-efdd4e7c5dccef21.yaml0000644000175000017500000000014400000000000030452 0ustar00coreycorey00000000000000--- features: - | Added support for availability zones. Can now create a LB in a specific AZ. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/add-insert-headers-a6fd80c837a89536.yaml0000644000175000017500000000012400000000000030614 0ustar00coreycorey00000000000000--- features: - | Adds the ability to set the insertion headers on listeners. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/add-l7-support-05a790bc2965c38f.yaml0000644000175000017500000000010100000000000027715 0ustar00coreycorey00000000000000--- features: - | Adds L7 policy support to the dashboard. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/add-member-backup-32e2ec2553c1ba24.yaml0000644000175000017500000000010200000000000030427 0ustar00coreycorey00000000000000--- features: - | Adds the ability to set member as backup. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/add-timeout-options-8988fc477fa46d31.yaml0000644000175000017500000000012600000000000031067 0ustar00coreycorey00000000000000--- features: - | Adds the ability to set the timeout options on listeners. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/add-udp-support-acb1a22fb605d3a8.yaml0000644000175000017500000000020600000000000030363 0ustar00coreycorey00000000000000--- features: - | Added UDP protocol support in listeners and pools, added UDP-CONNECT method for health-monitor resources. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/add-x-forwarded-proto-e30b52a3f853ed62.yaml0000644000175000017500000000015100000000000031320 0ustar00coreycorey00000000000000--- features: - | Adds the ability to set the X-Forwarded-Proto insertion header on listeners. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/auto-refresh-detail-pages-26166d5d9c26edee.yaml0000644000175000017500000000012300000000000032244 0ustar00coreycorey00000000000000--- features: - | Adds the ability to auto refresh detail pages upon action. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/bp-horizon-lbaas-v2-ui-ba7e4c97a0460f85.yaml0000644000175000017500000000160500000000000031333 0ustar00coreycorey00000000000000--- 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. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/cascade-delete-e4c9d80a31076540.yaml0000644000175000017500000000030100000000000027667 0ustar00coreycorey00000000000000--- features: - | Allow cascade deletion of load balancer. other: - | This changed the default behavior of load balancer deletion from non-cascade deletion to cascade deletion. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/drop-py-2-7-f3372b5c26171513.yaml0000644000175000017500000000033300000000000026663 0ustar00coreycorey00000000000000--- 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. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/edit-default-pool-on-listener-206d8dfeea135360.yaml0000644000175000017500000000011200000000000032756 0ustar00coreycorey00000000000000--- features: - | You can now change the default pool on listeners. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/filter-select-65160dcbe699a96d.yaml0000644000175000017500000000061100000000000027772 0ustar00coreycorey00000000000000--- 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.././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/fix-auth-url-barbican-client-d41b03419fb31ba4.yaml0000644000175000017500000000012300000000000032531 0ustar00coreycorey00000000000000--- fixes: - Fixed an issue where TERMINATED_HTTPS listener type was greyed out. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/fix-flavor-no-flavor-profile-c3e82325f16d5ab8.yaml0000644000175000017500000000043000000000000032627 0ustar00coreycorey00000000000000--- 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. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/flavor-support-0195a486faa16b7f.yaml0000644000175000017500000000022500000000000030220 0ustar00coreycorey00000000000000--- features: - | Add load balancer flavor support. issues: - | The octavia-dashboard requires openstacksdk > 0.24.0 for flavor support. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/initial-octavia-dashboard-35d1d7f923473f21.yaml0000644000175000017500000000341600000000000032067 0ustar00coreycorey00000000000000--- 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. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/list-pools-on-lb-details-page-eb0400bdb2b3650f.yaml0000644000175000017500000000016000000000000032715 0ustar00coreycorey00000000000000--- features: - | Pools attached to a load balancer are now listed on the load balancer details page. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/notes/pool-selection-hint-7f282ba1fa014d8c.yaml0000644000175000017500000000016200000000000031161 0ustar00coreycorey00000000000000--- features: - | The pool name is now visible in pool selection drop downs in addition to the pool ID. ././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/source/0000755000175000017500000000000000000000000022265 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/source/_static/0000755000175000017500000000000000000000000023713 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/_static/.placeholder0000644000175000017500000000000000000000000026164 0ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/source/_templates/0000755000175000017500000000000000000000000024422 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/_templates/.placeholder0000644000175000017500000000000000000000000026673 0ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/conf.py0000644000175000017500000001173100000000000023567 0ustar00coreycorey00000000000000# -*- 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 repository_name = 'openstack/octavia-dashboard' bug_project = '909' bug_tag = 'doc' # 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 = u'2017, Octavia Developers' author = u'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 = 'sphinx' # 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', u'octavia-dashboard Documentation', u'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', u'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', u'octavia-dashboard Documentation', author, 'octavia-dashboard', 'One line description of project.', 'Miscellaneous'), ] # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/index.rst0000644000175000017500000000137000000000000024127 0ustar00coreycorey00000000000000.. 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 train stein rocky queens ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0080154 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/0000755000175000017500000000000000000000000023524 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0080154 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/de/0000755000175000017500000000000000000000000024114 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/de/LC_MESSAGES/0000755000175000017500000000000000000000000025701 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/de/LC_MESSAGES/releasenotes.po0000644000175000017500000000410200000000000030727 0ustar00coreycorey00000000000000# Robert Simai , 2018. #zanata # Andreas Jaeger , 2019. #zanata # Robert Simai , 2019. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-10-03 15:01+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-26 06:46+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 "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 "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 "Upgrade Notes" msgstr "Aktualisierungsnotizen" ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0080154 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/en_GB/0000755000175000017500000000000000000000000024476 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/en_GB/LC_MESSAGES/0000755000175000017500000000000000000000000026263 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po0000644000175000017500000003016600000000000031322 0ustar00coreycorey00000000000000# Andi Chandler , 2017. #zanata # Andi Chandler , 2018. #zanata # Andi Chandler , 2019. #zanata # Andi Chandler , 2020. #zanata msgid "" msgstr "" "Project-Id-Version: octavia-dashboard\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-04-05 08:03+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2020-04-07 08:33+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 "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 "4.0.0.0rc1-16" msgstr "4.0.0.0rc1-16" 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 load balancer flavor support." msgstr "Add load balancer flavour support." 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 "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 "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 "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 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 "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 "Upgrade Notes" msgstr "Upgrade Notes" msgid "You can now change the default pool on listeners." msgstr "You can now change the default pool on listeners." ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0080154 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/id/0000755000175000017500000000000000000000000024120 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/id/LC_MESSAGES/0000755000175000017500000000000000000000000025705 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/id/LC_MESSAGES/releasenotes.po0000644000175000017500000002734300000000000030747 0ustar00coreycorey00000000000000# 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)." ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0080154 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/ko_KR/0000755000175000017500000000000000000000000024531 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/ko_KR/LC_MESSAGES/0000755000175000017500000000000000000000000026316 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po0000644000175000017500000003126000000000000031351 0ustar00coreycorey00000000000000# 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 "리스너에서 디폴트 풀을 이제 변경할 수 있습니다." ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0080154 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/zh_CN/0000755000175000017500000000000000000000000024525 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/zh_CN/LC_MESSAGES/0000755000175000017500000000000000000000000026312 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/zh_CN/LC_MESSAGES/releasenotes.po0000644000175000017500000001747700000000000031363 0ustar00coreycorey00000000000000# 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 "允许改变监听器的默认资源池。" ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0080154 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/zh_TW/0000755000175000017500000000000000000000000024557 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000003200000000000011450 xustar000000000000000026 mtime=1586806716.08401 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/zh_TW/LC_MESSAGES/0000755000175000017500000000000000000000000026344 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/locale/zh_TW/LC_MESSAGES/releasenotes.po0000644000175000017500000001750200000000000031402 0ustar00coreycorey00000000000000# 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 "允許改變監聽器的預設資源池。" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/queens.rst0000644000175000017500000000022300000000000024314 0ustar00coreycorey00000000000000=================================== Queens Series Release Notes =================================== .. release-notes:: :branch: stable/queens ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/rocky.rst0000644000175000017500000000022100000000000024141 0ustar00coreycorey00000000000000=================================== Rocky Series Release Notes =================================== .. release-notes:: :branch: stable/rocky ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/stein.rst0000644000175000017500000000022100000000000024134 0ustar00coreycorey00000000000000=================================== Stein Series Release Notes =================================== .. release-notes:: :branch: stable/stein ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/train.rst0000644000175000017500000000017600000000000024140 0ustar00coreycorey00000000000000========================== Train Series Release Notes ========================== .. release-notes:: :branch: stable/train ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/releasenotes/source/unreleased.rst0000644000175000017500000000016000000000000025143 0ustar00coreycorey00000000000000============================== Current Series Release Notes ============================== .. release-notes:: ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/requirements.txt0000644000175000017500000000070000000000000021555 0ustar00coreycorey00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. horizon>=17.1.0 # Apache-2.0 Babel!=2.4.0,>=2.3.4 # BSD openstacksdk>=0.24.0 # Apache-2.0 oslo.log>=3.36.0 # Apache-2.0 pbr!=2.1.0,>=2.0.0 # Apache-2.0 python-barbicanclient>=4.5.2 # Apache-2.0 python-keystoneclient>=3.22.0 # Apache-2.0 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0880096 octavia-dashboard-4.1.0.dev21/setup.cfg0000644000175000017500000000235600000000000020123 0ustar00coreycorey00000000000000[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/ 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 :: 3 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 [files] packages = octavia_dashboard [build_sphinx] source-dir = doc/source build-dir = doc/build all_files = 1 [upload_sphinx] upload-dir = doc/build/html [pbr] autodoc_tree_index_modules = False autodoc_tree_excludes = setup.py octavia_dashboard/tests octavia_dashboard/enabled octavia_dashboard/locale octavia_dashboard/static octavia_dashboard/conf octavia_dashboard/local_settings.d octavia_dashboard/post_install.sh octavia_dashboard/karma.conf.js autodoc_index_modules = False autodoc_exclude_modules = octavia_dashboard.tests.* octavia_dashboard.enabled.* api_doc_dir = contributor/modules [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/setup.py0000644000175000017500000000200600000000000020004 0ustar00coreycorey00000000000000# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT import setuptools # In python < 2.7.4, a lazy loading of package `pbr` will break # setuptools if some other modules registered functions in `atexit`. # solution from: http://bugs.python.org/issue15881#msg170215 try: import multiprocessing # noqa except ImportError: pass setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/test-requirements.txt0000644000175000017500000000077500000000000022546 0ustar00coreycorey00000000000000# The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. hacking>=1.1.0,<1.2.0 # Apache-2.0 coverage!=4.4,>=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 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/tox.ini0000644000175000017500000000501400000000000017607 0ustar00coreycorey00000000000000[tox] minversion = 2.5.0 envlist = py3,pep8,eslint,karma skipsdist = True [testenv] basepython = python3 usedevelop = True install_command = pip install {opts} {packages} setenv = VIRTUAL_ENV={envdir} CLIENT_NAME=octavia-dashboard DJANGO_SETTINGS_MODULE=octavia_dashboard.tests.settings deps = -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt whitelist_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] whitelist_externals = rm deps = -c{env:UPPER_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} whitelist_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] whitelist_externals = rm deps = -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/requirements.txt -r{toxinidir}/doc/requirements.txt 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 # (because it is not easy to avoid this in openstack_dashboard.test.settings) show-source = True ignore = E123,E125,F405 builtins = _ exclude=.venv,.git,.tox,.tmp,dist,doc,*lib/python*,*egg,build,node_modules [testenv:lower-constraints] deps = -c{toxinidir}/lower-constraints.txt -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1586806716.0880096 octavia-dashboard-4.1.0.dev21/zuul.d/0000755000175000017500000000000000000000000017515 5ustar00coreycorey00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1586806714.0 octavia-dashboard-4.1.0.dev21/zuul.d/projects.yaml0000644000175000017500000000047000000000000022233 0ustar00coreycorey00000000000000- project: templates: - check-requirements - horizon-non-primary-django-jobs - horizon-nodejs10-jobs - openstack-lower-constraints-jobs - openstack-python3-ussuri-jobs-horizon - publish-openstack-docs-pti - release-notes-jobs-python3 gate: fail-fast: true