pax_global_header00006660000000000000000000000064143705467660014534gustar00rootroot0000000000000052 comment=0e656572a605dcb5c2f34d0f6a5c13d0589f396e softlayer-python-6.1.4/000077500000000000000000000000001437054676600150735ustar00rootroot00000000000000softlayer-python-6.1.4/.gitattributes000066400000000000000000000010221437054676600177610ustar00rootroot00000000000000# Set the default behavior, in case people don't have core.autocrlf set. * text=auto # Language aware diff headers # https://tekin.co.uk/2020/10/better-git-diff-output-for-ruby-python-elixir-and-more # https://gist.github.com/tekin/12500956bd56784728e490d8cef9cb81 *.css diff=css *.html diff=html *.py diff=python *.md diff=markdown # Declare files that will always have CRLF line endings on checkout. *.sln text eol=crlf # Denote all files that are truly binary and should not be modified. *.png binary *.jpg binary softlayer-python-6.1.4/.github/000077500000000000000000000000001437054676600164335ustar00rootroot00000000000000softlayer-python-6.1.4/.github/ISSUE_TEMPLATE/000077500000000000000000000000001437054676600206165ustar00rootroot00000000000000softlayer-python-6.1.4/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000011451437054676600233110ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: Bug assignees: '' --- > Reminder: No username or APIkeys should be added to these issues, as they are public. **Describe the bug** A clear and concise description of what the bug is. Include the command you used, make sure to include the `-v` flag, as that information is very helpful. Ex: `slcli -v vs list` **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Version** Include the output of `slcli --version` softlayer-python-6.1.4/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000012511437054676600243420ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: New Feature assignees: '' --- > REMINDER: Never add usernames or apikeys in these issues, as they are public. **What are you trying to do?** A brief explanation of what you are trying to do. Could be something simple like `slcli vs list` doesn't support a filter you need. Or more complex like recreating some functionality that exists in the cloud.ibm.com portal **Screen shots** If the functionality you want exists in the portal, please add a screenshot so we have a better idea of what you need. **Additional context** Add any other context or screenshots about the feature request here. softlayer-python-6.1.4/.github/dependabot.yml000066400000000000000000000005631437054676600212670ustar00rootroot00000000000000# Use `allow` to specify which dependencies to maintain # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-update version: 2 updates: - package-ecosystem: "pip" directory: "/" schedule: interval: "weekly" commit-message: prefix: "pip prod" prefix-development: "pip dev" include: "scope"softlayer-python-6.1.4/.github/workflows/000077500000000000000000000000001437054676600204705ustar00rootroot00000000000000softlayer-python-6.1.4/.github/workflows/codeql-analysis.yml000066400000000000000000000046171437054676600243130ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ master ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] schedule: - cron: '41 6 * * 5' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'python' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - name: Checkout repository uses: actions/checkout@v2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 softlayer-python-6.1.4/.github/workflows/documentation.yml000066400000000000000000000011451437054676600240650ustar00rootroot00000000000000name: documentation on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: [3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r tools/test-requirements.txt - name: Documentation Checks run: | python docCheck.py softlayer-python-6.1.4/.github/workflows/release.yml000066400000000000000000000026121437054676600226340ustar00rootroot00000000000000name: Release Snapcraft and PyPi on: release: types: [published] jobs: snap-release: runs-on: ubuntu-18.04 strategy: matrix: arch: ['armhf','amd64','arm64','ppc64el','s390x'] steps: - name: Install Snapcraft uses: samuelmeuli/action-snapcraft@v1.2.0 with: snapcraft_token: ${{ secrets.snapcraft_token }} - name: Push to stable run: | VERSION=`snapcraft list-revisions slcli --arch ${{ matrix.arch }} | grep "edge\*" | awk '{print $1}'` echo Publishing $VERSION on ${{ matrix.arch }} snapcraft release slcli $VERSION stable build-n-publish: name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Set up Python 3.8 uses: actions/setup-python@v2 with: python-version: 3.8 - name: Install pypa/build run: >- python -m pip install build --user - name: Build a binary wheel and a source tarball run: >- python -m build --sdist --wheel --outdir dist/ . - name: Publish 📦 to Test PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.CGALLO_PYPI }} repository_url: https://upload.pypi.org/legacy/ softlayer-python-6.1.4/.github/workflows/test_pypi_release.yml000066400000000000000000000016701437054676600247370ustar00rootroot00000000000000# https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/ name: Publish 📦 to TestPyPI on: push: branches: [test-pypi ] jobs: build-n-publish: name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI runs-on: ubuntu-latest steps: - uses: actions/checkout@master - name: Set up Python 3.8 uses: actions/setup-python@v2 with: python-version: 3.8 - name: Install pypa/build run: >- python -m pip install build --user - name: Build a binary wheel and a source tarball run: >- python -m build --sdist --wheel --outdir dist/ . - name: Publish 📦 to Test PyPI uses: pypa/gh-action-pypi-publish@master with: password: ${{ secrets.CGALLO_TEST_PYPI }} repository_url: https://test.pypi.org/legacy/softlayer-python-6.1.4/.github/workflows/tests.yml000066400000000000000000000025031437054676600223550ustar00rootroot00000000000000name: Tests on: push: branches: [ master ] pull_request: branches: [ master ] jobs: test: runs-on: ubuntu-latest strategy: matrix: python-version: [3.7,3.8,3.9,'3.10',3.11] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v1 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r tools/test-requirements.txt - name: Tox Test run: tox -e py coverage: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v1 with: python-version: 3.9 - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r tools/test-requirements.txt - name: Tox Coverage run: tox -e coverage analysis: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v1 with: python-version: 3.9 - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r tools/test-requirements.txt - name: Tox Analysis run: tox -e analysis softlayer-python-6.1.4/.gitignore000066400000000000000000000002231437054676600170600ustar00rootroot00000000000000.DS_Store *.swp Thumbs.db .svn ._* *.pyc .coverage htmlcov cover/* .tox docs/_build/* build/* dist/* *.egg-info .cache .idea .pytest_cache/* slcli softlayer-python-6.1.4/.mailmap000066400000000000000000000000521437054676600165110ustar00rootroot00000000000000Christopher Gallo softlayer-python-6.1.4/.readthedocs.yml000066400000000000000000000011141437054676600201560ustar00rootroot00000000000000# .readthedocs.yml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Build documentation in the docs/ directory with Sphinx sphinx: builder: htmldir configuration: docs/conf.py # Build documentation with MkDocs #mkdocs: # configuration: mkdocs.yml # Optionally build your docs in additional formats such as PDF and ePub formats: all # Optionally set the version of Python and requirements required to build your docs python: version: 3.7 install: - requirements: docs/requirements.txt softlayer-python-6.1.4/CHANGELOG.md000066400000000000000000001605021437054676600167100ustar00rootroot00000000000000# Change Log ## [6.1.3] - 2022-11-30 #### What's Changed * New Command: Hardware notifications by @caberos in https://github.com/softlayer/softlayer-python/pull/1756 * New Command: virtual notifications by @caberos in https://github.com/softlayer/softlayer-python/pull/1758 * Change regex in rich text in simple option in help text by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1759 * pip prod(deps): bump rich from 12.5.1 to 12.6.0 by @dependabot in https://github.com/softlayer/softlayer-python/pull/1760 * add more information to vs credentials by @caberos in https://github.com/softlayer/softlayer-python/pull/1762 * Fixed maxint issue by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1765 * Added csv output format by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1766 * add more information on hw credentials by @caberos in https://github.com/softlayer/softlayer-python/pull/1767 * Delete twitter link in documentation by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1769 * new command hw create-credential by @caberos in https://github.com/softlayer/softlayer-python/pull/1774 * fix the hw credential error by @caberos in https://github.com/softlayer/softlayer-python/pull/1781 * Added test suite for py311 by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1784 * New feature to change theme in slcli like dark, light o maintain in default by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1775 * Match `virtual detail --prices` option with `hardware detail --prices` option by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1780 * Fixing preset-list pricing table by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1782 * fix the call api cannot handle empty results by @caberos in https://github.com/softlayer/softlayer-python/pull/1789 * Debug output changed to a valid JSON by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1791 * slcli hw add-notifications crashes with a bad user by @caberos in https://github.com/softlayer/softlayer-python/pull/1786 * del-notification commands, rename the commands to notifications-add by @caberos in https://github.com/softlayer/softlayer-python/pull/1785 * Add --extras to slcli order quote by @caberos in https://github.com/softlayer/softlayer-python/pull/1792 * An error is displaying for volume with replica in slcli for Active pr… by @caberos in https://github.com/softlayer/softlayer-python/pull/1794 **Full Changelog**: https://github.com/softlayer/softlayer-python/compare/v6.1.2...v6.1.3 ## [6.1.2] - 2022-09-23 #### What's Changed * Snapcraft: Updated to Core22 and add homeishome-launch by @kz6fittycent in https://github.com/softlayer/softlayer-python/pull/1740 * Add status, create date and domain columns in `slcli vs list command` by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1728 * New command: ipsec cancel by @caberos in https://github.com/softlayer/softlayer-python/pull/1729 * New command: subnet clear-route by @caberos in https://github.com/softlayer/softlayer-python/pull/1738 * Deprecate slcli hw guests by @caberos in https://github.com/softlayer/softlayer-python/pull/1736 * Remove real usersnames from test fixtrues by @caberos in https://github.com/softlayer/softlayer-python/pull/1743 * Fix tox request.get hangout issue by @caberos in https://github.com/softlayer/softlayer-python/pull/1746 * add vs user-access command by @caberos in https://github.com/softlayer/softlayer-python/pull/1741 * Update Help message for commands that take in multiple arguments by @caberos in https://github.com/softlayer/softlayer-python/pull/1748 * Error with slcli order item-list by @caberos in https://github.com/softlayer/softlayer-python/pull/1751 * deprecate sl `autoscale` by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1753 * Unhandled error running a subcommand in slcli by @caberos in https://github.com/softlayer/softlayer-python/pull/1754 **Full Changelog**: https://github.com/softlayer/softlayer-python/compare/v6.1.1...v6.1.2 ## [6.1.1] - 2022-08-18 #### What's Changed * v6.1.0 Changelog and version bump by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1674 * item-list fix by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1679 * updating release job to actually publish to pypi by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1680 * Update command - slcli object-storage endpoints by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1685 * add the block volume-options command by @caberos in https://github.com/softlayer/softlayer-python/pull/1681 * add the file volume-options command by @caberos in https://github.com/softlayer/softlayer-python/pull/1684 * fixed issues where a message warned users about closing datacenter by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1688 * Enable --format=raw and fixes table width by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1689 * Update `slcli hardware sensor` by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1691 * Improved successful response to command - slcli vs cancel by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1695 * Fixed an issue with printing tables that contained empty items by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1697 * Added a dependabot scanner by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1699 * block|file volume-options improvements by @caberos in https://github.com/softlayer/softlayer-python/pull/1700 * Option create-options in commands hardware and dedicatedhost fixed by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1703 * pip prod(deps): bump rich from 12.3.0 to 12.5.1 by @dependabot in https://github.com/softlayer/softlayer-python/pull/1704 * block/file volume-options improvements 2 by @caberos in https://github.com/softlayer/softlayer-python/pull/1702 * New command ipsec order by @caberos in https://github.com/softlayer/softlayer-python/pull/1698 * block/file volume-options improvement 3 by @caberos in https://github.com/softlayer/softlayer-python/pull/1705 * Command slcli vlan create - displaying an error message by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1707 * New Command: user device-access by @caberos in https://github.com/softlayer/softlayer-python/pull/1712 * Command slcli vlan edit accept that we do not send any parameters by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1709 * Updated command - slcli vlan list by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1713 * `slcli block subnets-list` command display an error message by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1716 * add user remove-access command by @caberos in https://github.com/softlayer/softlayer-python/pull/1717 * Add Devices with Trunks to vlan detail by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1721 * slcli hardware reflash-firmware command does not display success message by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1724 * Fix bug with command - slcli cdn edit by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1726 #### New Contributors * @dependabot made their first contribution in https://github.com/softlayer/softlayer-python/pull/1704 **Full Changelog**: https://github.com/softlayer/softlayer-python/compare/v6.1.0...v6.1.1 ## [6.1.0] - 2022-06-30 #### Major Updates * [Rich](https://github.com/Textualize/rich) tables by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1646 * [Rich](https://github.com/Textualize/rich) Text support by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1635 Rich Text and Rich Tables will modernize the output of the SLCLI to be a little nicer to look at, with colors and other highlighting. ![image](https://user-images.githubusercontent.com/7408017/176753783-f6a4a43a-53ac-4600-a24f-21362f152747.png) ![image](https://user-images.githubusercontent.com/7408017/176753845-32af33f0-454f-4bab-ac63-1ae3db788ede.png) #### What's Changed * slcli licenses is missing the help text by @caberos in https://github.com/softlayer/softlayer-python/pull/1605 * Add a warning if user orders in a POD that is being closed by @caberos in https://github.com/softlayer/softlayer-python/pull/1600 * updated number of updates in the command account event-detail by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1609 * Add an orderBy filter to slcli vlan list by @caberos in https://github.com/softlayer/softlayer-python/pull/1599 * Add options to print a specific table in command slcli account events by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1611 * Update global ip assign/unassign to use new API by @caberos in https://github.com/softlayer/softlayer-python/pull/1614 * Ability to route/unroute subnets by @caberos in https://github.com/softlayer/softlayer-python/pull/1615 * Improved successful response to command - slcli account cancel-item by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1617 * Improved successful response to command - slcli virtual edit by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1618 * Improved successful response to command - slcli vlan cancel by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1619 * Mishandling of domain and hostname data in `slcli account item-detail` by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1621 * Unable to get VSI details when last TXN is "Software install is finis… by @caberos in https://github.com/softlayer/softlayer-python/pull/1625 * new command on autoscale delete by @caberos in https://github.com/softlayer/softlayer-python/pull/1628 * Incorrect table title is displayed when an Auto Scale Group is scaled to reduce members by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1629 * slcli autoscale create by @caberos in https://github.com/softlayer/softlayer-python/pull/1623 * Soap transport by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1626 * fix issue on loadbal order command by @caberos in https://github.com/softlayer/softlayer-python/pull/1633 * Policy is not added when an AutoScale Group is created by @caberos in https://github.com/softlayer/softlayer-python/pull/1637 * When `slcli event-log` not return any event log the command display an error by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1641 * add new columns on vlan list(premium, tags) by @caberos in https://github.com/softlayer/softlayer-python/pull/1645 * fixed documentation build issues by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1648 * Improved successful response to command - slcli licenses cancel by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1653 * update the firewall list by @caberos in https://github.com/softlayer/softlayer-python/pull/1649 * Updated readme by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1656 * Update `slcli firewall detail` to handle multi vlan firewalls by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1651 * New command for getting duplicate convert status by @ko101 in https://github.com/softlayer/softlayer-python/pull/1655 * Fixed TOX errors by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1661 * add a new feature to get all cloud object storage by @caberos in https://github.com/softlayer/softlayer-python/pull/1662 * Update `slcli report bandwidth` command by @BrianSantivanez in https://github.com/softlayer/softlayer-python/pull/1664 * add firewall monitoring command by @caberos in https://github.com/softlayer/softlayer-python/pull/1657 * add a new command on block object-storage details by @caberos in https://github.com/softlayer/softlayer-python/pull/1666 * slcli account bandwidth-pools-detail command displays an error with b… by @caberos in https://github.com/softlayer/softlayer-python/pull/1670 * new feature block object-storage permissions command by @caberos in https://github.com/softlayer/softlayer-python/pull/1668 * fix the vlan table by @caberos in https://github.com/softlayer/softlayer-python/pull/1672 #### New Contributors * @BrianSantivanez made their first contribution in https://github.com/softlayer/softlayer-python/pull/1629 **Full Changelog**: https://github.com/softlayer/softlayer-python/compare/v6.0.2...v6.1.0 ### [6.0.2] - 2022-03-30 #### What's Changed * New Command slcli hardware|virtual monitoring by @caberos in https://github.com/softlayer/softlayer-python/pull/1593 * When listing datacenters/pods, mark those that are closing soon. by @caberos in https://github.com/softlayer/softlayer-python/pull/1597 **Full Changelog**: https://github.com/softlayer/softlayer-python/compare/v6.0.1...v6.0.2 ## [6.0.1] - 2022-03-11 #### What's Changed * Replace the use of ptable with prettytable by @dvzrv in https://github.com/softlayer/softlayer-python/pull/1584 * Bandwidth pool management by @caberos in https://github.com/softlayer/softlayer-python/pull/1582 * Add id in the result in the command bandwidth-pools by @edsonarios in https://github.com/softlayer/softlayer-python/pull/1586 * Datacenter closure report by @allmightyspiff in https://github.com/softlayer/softlayer-python/pull/1592 * fix to errors in slcli hw create-options by @caberos in https://github.com/softlayer/softlayer-python/pull/1594 **Full Changelog**: https://github.com/softlayer/softlayer-python/compare/v5.9.9...v6.0.1 6.0.0 was skipped. ## [5.9.9] - 2022-02-04 https://github.com/softlayer/softlayer-python/compare/v5.9.8...v5.9.9 #### Improvements - Add loadbalancer timeout values #1576 - Add pricing date to slcli order preset-list #1578 #### New Commands - `slcli vlan create-options` add new feature on vlan #1572 - `slcli account bandwidth-pools` Bandwidth pool features #1579 ## [5.9.8] - 2021-12-07 https://github.com/softlayer/softlayer-python/compare/v5.9.7...v5.9.8 #### Improvements - Fix code blocks formatting of The Solution section docs #1534 - Add retry decorator to documentation #1535 - Updated utility docs #1536 - Add Exceptions to Documentation #1537 - Forces specific encoding on XMLRPC requests #1543 - Add sensor data to hardware #1544 - Ignoring f-string related messages for tox for now #1548 - Fix account events #1546 - Improved loadbal details #1549 - Fix initialized accountmanger #1552 - Fix hw billing reports 0 items #1556 - Update API docs link and remove travisCI mention #1557 - Fix errors with vs bandwidth #1563 - Add Item names to vs billing report #1564 - Mapping is now in collections.abc #1565 - fix vs placementgroup list #1567 - fixed up snapshot-notification cli commands #1569 #### New Commands - loadbal l7policies #1553 + ` slcli loadbal l7policies --protocol-id` + `slcli loadbal l7policies` - Snapshot notify #1554 + `slcli file|block snapshot-set-notification` + `slcli file|block snapshot-get-notification-status` ## [5.9.7] - 2021-08-04 https://github.com/softlayer/softlayer-python/compare/v5.9.6...v5.9.7 #### Improvements - Fixed some doc block issues when generating HTML #1513 - Updates to the Release workflow for publishing to test pypi #1514 - Adding in CodeQL Analysis #1517 - Create SECURITY.md #1518 - Fix the network space is empty on subnet detail #1523 - Prevents SLCLI_VERSION environment variable from breaking things #1527 - Refactor loadbal order-options #1521 - slcli server create-options dal13 Error #1526 #### New Commands - add new feature on vlan cli #1499 + `slcli vlan create` ## [5.9.6] - 2021-07-05 https://github.com/softlayer/softlayer-python/compare/v5.9.5...v5.9.6 #### Improvements - Updated snap to core20 and edited README #1494 - Add a table result for `slcli hw upgrade` output. #1488 - Remove block/file interval option for replica volume. #1497 - `slcli vlan cancel` should report if a vlan is automatic. #1495 - New method to manage how long text is in output tables. #1506 - Fix Tox-analysis issues. #1510 #### New Commands - add new email feature #1483 + `slcli email list` + `slcli email detail` + `slcli email edit` - `slcli vlan cancel` - Add slcli account licenses #1501 + `slcli account licenses` - Create a new commands on slcli that create/cancel a VMware licenses #1504 + `slcli licenses create` + `slcli licenses cancel` ## [5.9.5] - 2021-05-25 https://github.com/softlayer/softlayer-python/compare/v5.9.4...v5.9.5 #### Improvements - Changed a testing domain to one that really doesnt exist #1492 - Fix Incomplete notes field for file and block #1484 - Show component versions on hw detail #1470 - Add the firewall information on slcli firewall detail #1475 - Add an --orderBy parameters to call-api #1459 - Add image detail transaction data #1479 ## [5.9.4] - 2021-04-27 https://github.com/softlayer/softlayer-python/compare/v5.9.3...v5.9.4 #### New Commands - `slcli hw authorize-storage` #1439 - `slcli order quote-save` #1451 #### Improvements - Refactored managers.ordering_manager.verify_quote() to work better with the REST endpoing #1430 - Add routers for each DC in slcli hw create-options #1432 - Add preset datatype in slcli virtual detail #1435 - Add upgrade option to slcli hw. #1437 - Ibmcloud authentication support #1315 / #1447 + `slcli config setup --ibmid` + `slcli config setup --sso` + `slcli config setup --cloud_key` + `slcli config setup --classic_key` - Refactor slcli hw detail prices. #1443 - Updated contributing guide #1458 - Add the Hardware components on "slcli hardware detail" #1452 - Add billing and lastTransaction on hardware detail #1446 - Forced reserved capacity guests to be monthly #1454 - Removing the rwhois commands #1456 - Added automation to publish to test-pypi #1467 - Updating author_email to SLDN distro list #1469 - Add the option to add and upgrade the hw disk. #1455 - Added a utility to merge objectFilters, #1468 - Fixes shift+ins when pasteing into a password field for windows users. #1460 - Add Billing and lastTransaction on slcli virtual detail #1466 - Fixing 'import mock' pylint issues #1476 ## [5.9.3] - 2021-03-03 https://github.com/softlayer/softlayer-python/compare/v5.9.2...v5.9.3 #### New Commands - `slcli file|block disaster-recovery-failover` #1407 #### Improvements - Unit testing for large integers #1403 - Add Multi factor authentication to users list #1408 - Add pagination to object storage list accounts. #1411 - Add username lookup to slcli object-storage credential #1415 - Add IOPs data to slcli block volume-list. #1418 - Add 2FA and classic APIKeys fields to slcli user list as default values #1421 - Add a flags in the report bandwidth #1420 - Add the option network component by router to slcli hw create. #1422 - Add slcli vs create by router data. #1414 - Add testing and support for python 3.9. #1429 - Checking for TermLength on prices #1428 ## [5.9.2] - 2020-12-03 https://github.com/softlayer/softlayer-python/compare/v5.9.1...v5.9.2 #### New Commands - `slcli account orders` #1349 - `slcli order lookup` #1354 #### Improvements - Ordering price information improvements. #1319 - refactor vsi create-option #1337 - Add Invoice Item id as parameter in `slcli account item-detail` command - Added order lookup command to block and file orders. #1350 - Add prices to vs create-options. #1351 - Allow orders without a location if needed #1356 - Refactor file and block commands to use the username resolver #1357 - Fix create subnet static for ipv4 price. #1358 - moved snapcraft readme #1363 - Update snapcraft.yaml #1365 - Updated documentation on how to deal with KeyError #1366 - Fix order item-list --prices location #1360 - Removed Nessus scanner from docs and examples #1368 - Fix subnet list. #1379 - Fixed analysis/flake8 tests #1381 - Remove the `-a` option from `slcli user create`. Only the user themselves can create an API key now. #1377 ## [5.9.1] - 2020-09-15 https://github.com/softlayer/softlayer-python/compare/v5.9.0...v5.9.1 - Fix the ha option for firewalls, add and implement unit test #1327 - BluePages_Search and IntegratedOfferingTeam_Region don't need SoftLayer_ prefix #972 - Fix new TOX issues #1330 - Add more unit test coverage #1331 - Set notes for network storage #1322 - Some improvements to the dns commands #999 + dns zone-list: added resourceRecordCount, added automatic pagination for large zones + dns record-list: fixed an issue where a record (like SRV types) that don't have a host would cause the command to fail - Renamed managers.storage.refresh_dep_dupe to SoftLayer.managers.storage.refresh_dupe #1342 to support the new API method. CLI commands now use this method. - #1295 added disk upgrade options for virtual guests ## [5.9.0] - 2020-08-03 https://github.com/softlayer/softlayer-python/compare/v5.8.9...v5.9.0 - #1280 Notification Management + slcli user notifications + slcli user edit-notifications - #828 Added networking options to slcli hw create-options + Refactored slcli hw create to use the ordering manager + Added --network option to slcli hw create for more granular network choices. + Deprecated --port-speed and --no-public . They still work for now, but will be removed in a future release. - #1298 Fix Unhandled exception in CLI - vs detail - #1309 Fix the empty lines in slcli vs create-options - #1301 Ability to list VirtualHost capable guests + slcli hardware guests + slcli vs list will show guests on VirtualHost servers - #875 added option to reload bare metal servers with LVM enabled - #874 Added Migrate command - #1313 Added support for filteredMask - #1305 Update docs links - #1302 Fix lots of whitespace slcli vs create-options - #900 Support for STDIN on creating and updating tickets. - #1318 add Drive number in guest drives details using the device number - #1323 add vs list hardware and all option ## [5.8.9] - 2020-07-06 https://github.com/softlayer/softlayer-python/compare/v5.8.8...v5.8.9 - #1252 Automated Snap publisher - #1230 Tag Management + slcli tags cleanup + slcli tags delete + slcli tags details + slcli tags list + slcli tags set + slcli tags taggable - #1285 Vlan editing functionality - #1287 Edit IP note and add ipAddress table in detail view - #1283 Subnet Tagging - #1291 Storage documentation updates - #1293 add system operation referenceCode in create-option ## [5.8.8] - 2020-05-18 https://github.com/softlayer/softlayer-python/compare/v5.8.7...v5.8.8 - #1266 Fixed ticket upload with REST endpoint - #1263 add the redundant/degraded option to hardware - #1262 Added `iter` option for ordering manager functions - #1264 Add Account planned, unplanned and announcement events - #1265 fixed pylint 2.5.0 errors - #1261 Fix AttributeError: 'NoneType' object has no attribute 'keys - #1256 Adding more github action tests, removing travis CI tests - #887 fix Response shows additional new lines (\n) in ticket details - #1241 Storage feature for virtual and hardware servers - #1242 Hardware and Virtual billing info - #1239 VPN subnet access to a use - #1254 added account billing-items/item-details/cancel-item commands ## [5.8.7] - 2020-03-26 https://github.com/softlayer/softlayer-python/compare/v5.8.5...v5.8.7 - #1222 Get load balancer (LBaaS) by name - #1221 Added version checker - #1227 Updated unit test suite for TravisCI to run properly - #1225 Add note about using multiple colon symbols not working when setting tags. - #1228 Support ordering [Dependent Duplicate Volumes](https://cloud.ibm.com/docs/BlockStorage?topic=BlockStorage-dependentduplicate) - #1233 Refactored File/Block managers to reduce duplicated code. - #1231 Added Refresh functions for Dependent Duplicate Volumes - #801 Added support for JSON styled parameters and object filters - #1234 Added ability to change which datacenters an image template was stored in ## [5.8.6] - Skipped ## [5.8.5] - 2020-01-29 https://github.com/softlayer/softlayer-python/compare/v5.8.4...v5.8.5 - #1195 Fixed an issue with `slcli vs dns-sync --ptr`. Added `slcli hw dns-sync` - #1199 Fix File Storage failback and failover. - #1198 Fix issue where the summary command fails due to None being provided as the datacenter name. - #1208 Added The following commands: - `slcli block volume-limits` - `slcli file volume-limits` - #1209 Add testing/CI for python 3.8. - #1212 Fix vs detail erroring on servers pending cancellation. - #1210 support subnet ACL management through cli + `slcli block subnets-list` + `slcli block subnets-assign` + `slcli block subnets-remove` - #1215 Added documentation for all SLCLI commands. ## [5.8.4] - 2019-12-20 https://github.com/softlayer/softlayer-python/compare/v5.8.3...v5.8.4 - #1199 Fix block storage failback and failover. - #1202 Order a virtual server private. ## [5.8.3] - 2019-12-11 https://github.com/softlayer/softlayer-python/compare/v5.8.2...v5.8.3 - #771 Fixed unicode errors in image list (for windows) - #1191 Fixed ordering virtual server dedicated from the CLI - #1155 Fixed capacity restriction when ordering storage quotes - #1192 Fixed hardware detail bandwidth allocation errors. ## [5.8.2] - 2019-11-15 - https://github.com/softlayer/softlayer-python/compare/v5.8.1...v5.8.2 + #1186 Fixed a unit test that could fail if the test took too long to run. + #1183 Added a check to ensure subnet and vlan options are properly added to the order for virtual servers. + #1184 Fixed a readme misspelling. + #1182 Fixed vs reboot unable to resolve vs names. + #1095 Handle missing Fixtures better for unit tests. ## [5.8.1] - 2019-10-11 - https://github.com/softlayer/softlayer-python/compare/v5.8.0...v5.8.1 + #1169 Drop python 2.7 support + #1170 Added CS# to ticket listing + #1162 Fixed issue looking up OS keyName instead of referenceCode + #627 Autoscale support * slcli autoscale detail * slcli autoscale edit * slcli autoscale list * slcli autoscale logs * slcli autoscale scale * slcli autoscale tag ## [5.8.0] - 2019-09-04 - https://github.com/softlayer/softlayer-python/compare/v5.7.2...v5.8.0 + #1143 Upgrade to prompt_toolkit >= 2 + #1003 Bandwidth Feature * slcli summary * slcli report bandwidth * slcli vs bandwidth * slcli hw bandwidth * Added bandwidth to VS and HW details page + #1146 DOCS: replace 'developer' with 'sldn' links + #1147 property 'contents' is not valid for 'SoftLayer_Ticket' when creating a ticket + #1139 cannot create static subnet with slcli + #1145 Refactor cdn network. + #1152 IBMID auth support + #1153, #1052 Transient VSI support + #1167 Removed legacy LoadBalancer command, added Citrix and IBM LBaaS commands. * slcli lb cancel * slcli lb detail * slcli lb health * slcli lb l7pool-add * slcli lb l7pool-del * slcli lb list * slcli lb member-add * slcli lb member-del * slcli lb ns-detail * slcli lb ns-list * slcli lb order * slcli lb order-options * slcli lb pool-add * slcli lb pool-del * slcli lb pool-edit + #1157 Remove VpnAllowedFlag. + #1160 Improve hardware cancellation to deal with additional cases ## [5.7.2] - 2019-05-03 - https://github.com/softlayer/softlayer-python/compare/v5.7.1...v5.7.2 + #1107 Added exception to handle json parsing error when ordering + #1068 Support for -1 when changing port speed + #1109 Fixed docs about placement groups + #1112 File storage endurance iops upgrade + #1101 Handle the new user creation exceptions + #1116 Fix order place quantity option + #1002 Invoice commands * account invoices * account invoice-detail * account summary + #1004 Event Notification Management commands * account events * account event-detail + #1117 Two PCIe items can be added at order time + #1121 Fix object storage apiType for S3 and Swift. + #1100 Event Log performance improvements. + #872 column 'name' was renamed to 'hostname' + #1127 Fix object storage credentials. + #1129 Fixed unexpected errors in slcli subnet create + #1134 Change encrypt parameters for importing of images. Adds root-key-crn + #208 Quote ordering commands * order quote * order quote-detail * order quote-list + #1113 VS usage information command * virtual usage + #1131 made sure config_tests dont actually make api calls. ## [5.7.1] - 2019-02-26 - https://github.com/softlayer/softlayer-python/compare/v5.7.0...v5.7.1 + #1089 removed legacy SL message queue commands + Support for Hardware reflash firmware CLI/Manager method ## [5.7.0] - 2019-02-15 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.6.4...v5.7.0 + #1099 Support for security group Ids + event-log cli command + #1069 Virtual Placement Group Support ``` slcli vs placementgroup --help Commands: create Create a placement group. create-options List options for creating a placement group. delete Delete a placement group. detail View details of a placement group. list List placement groups. ``` + #962 Rest Transport improvements. Properly handle HTTP exceptions instead of crashing. + #1090 removed power_state column option from "slcli server list" + #676 - ipv6 support for creating virtual guests * Refactored virtual guest creation to use Product_Order::placeOrder instead of Virtual_Guest::createObject, because createObject doesn't allow adding IPv6 + #882 Added table which shows the status of each url in object storage + #1085 Update provisionedIops reading to handle float-y values + #1074 fixed issue with config setup + #1081 Fix file volume-cancel + #1059 Support for SoftLayer_Hardware_Server::toggleManagementInterface * `slcli hw toggle-ipmi` ## [5.6.4] - 2018-11-16 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.6.3...v5.6.4 + #1041 Dedicated host cancel, cancel-guests, list-guests + #1071 added createDate and modifyDate parameters to sg rule-list + #1060 Fixed slcli subnet list + #1056 Fixed documentation link in image manager + #1062 Added description to slcli order ## [5.6.3] - 2018-11-07 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.6.0...v5.6.3 + #1065 Updated urllib3 and requests libraries due to CVE-2018-18074 + #1070 Fixed an ordering bug + Updated release process and fab-file ## [5.6.0] - 2018-10-16 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.5.3...v5.6.0 + #1026 Support for [Reserved Capacity](https://cloud.ibm.com/docs/virtual-servers?topic=virtual-servers-about-reserved-virtual-servers) * `slcli vs capacity create` * `slcli vs capacity create-guest` * `slcli vs capacity create-options` * `slcli vs capacity detail` * `slcli vs capacity list` + #1050 Fix `post_uri` parameter name on docstring + #1039 Fixed suspend cloud server order. + #1055 Update to use click 7 + #1053 Add export/import capabilities to/from IBM Cloud Object Storage to the image manager as well as the slcli. ## [5.5.3] - 2018-08-31 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.5.2...v5.5.3 + Added `slcli user delete` + #1023 Added `slcli order quote` to let users create a quote from the slcli. + #1032 Fixed vs upgrades when using flavors. + #1034 Added pagination to ticket list commands + #1037 Fixed DNS manager to be more flexible and support more zone types. + #1044 Pinned Click library version at >=5 < 7 ## [5.5.2] - 2018-08-31 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.5.1...v5.5.2 + #1018 Fixed hardware credentials. + #1019 support for ticket priorities + #1025 create dedicated host with gpu fixed. ## [5.5.1] - 2018-08-06 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.5.0...v5.5.1 - #1006, added paginations to several slcli methods, making them work better with large result sets. - #995, Fixed an issue displaying VLANs. - #1011, Fixed an issue displaying some NAS passwords - #1014, Ability to delete users ## [5.5.0] - 2018-07-09 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.4.4...v5.5.0 - Added a warning when ordering legacy storage volumes - Added documentation link to volume-order - Increased slcli output width limit to 999 characters - More unit tests - Fixed an issue canceling some block storage volumes - Fixed `slcli order` to work with network gateways - Fixed an issue showing hardware credentials when they do not exist - Fixed an issue showing addressSpace when listing virtual servers - Updated ordering class to support baremetal servers with multiple GPU - Updated prompt-toolkit as a fix for `slcli shell` - Fixed `slcli vlan detail` to not fail when objects don't have a hostname - Added user management ## [5.4.4] - 2018-04-18 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.4.3...v5.4.4 - fixed hw list not showing transactions - Re-factored RestTransport and XMLRPCTransport, logging is now only done in the DebugTransport - Added print_reproduceable to XMLRPCTransport and RestTransport, which should be very useful in printing out pure API calls. - Fixed an issue with RestTransport and locationGroupId ## [5.4.3] - 2018-03-30 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.4.2...v5.4.3 - Corrected to current create-options output - Allow ordering of account restricted presets - Added lookup function for datacenter names and ability to use `slcli order` with short DC names - Changed locatoinGroupId to check for None instead of empty string - Added a way to try to cancel montly bare metal immediately. THis is done by automatically updating the cancellation request. A human still needs to read the ticket and process it for the reclaim to complete. ## [5.4.2] - 2018-02-22 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.4.1...v5.4.2 - add GPU to the virtual create-options table - Remove 'virtual' from the hardware ready command. - Carefully check for the metric tracking id on virtual guests when building a bandwidth report. - Do not fail if the source or destination subnet mask does not exist for ipv6 rules. ## [5.4.1] - 2018-02-05 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.4.0...v5.4.1 - Improve error conditions when adding SSH keys - added type filters to package-list, auto-removes bluemix_services on package listing - Add boot mode option to virtual guest creation - Update documentation for security group rule add - Add fix for unsetting of values in edit SG rules ## [5.4.0] - 2018-01-15 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.3.2...v5.4.0 - Upgraded Requests and Urllib3 library to latest. This allows the library to make use of connection retries, and connection pools. This should prevent the client from crashing if the API gives a connection reset / connection timeout error - reworked wait_for_ready function for virtual, and added to hardware managers. - fixed block/file iops in the `slcli block|file detail` view - Added sub items to `hw detail --price`, removed reverse PTR entries ### Added to CLI - slcli order ``` $ ./slcli order Usage: slcli order [OPTIONS] COMMAND [ARGS]... Options: -h, --help Show this message and exit. Commands: category-list List the categories of a package. item-list List package items used for ordering. package-list List packages that can be ordered via the... package-locations List Datacenters a package can be ordered in. place Place or verify an order. preset-list List package presets. ``` ## [5.3.2] - 2017-12-18 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.3.1...v5.3.2 - Expanded `@retry` useage to a few areas in the hardware manager - Added INTERVAL options to block and file replication - Fixed pricing error on `hw detail --price` - Added sub items to `hw detail --price`, removed reverse PTR entries ### Added to CLI - slcli dedicatedhost ## [5.3.1] - 2017-12-07 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.3.0...v5.3.1 - Added support for storage volume modifications ### Added to CLI - slcli block volume-modify - slcli file volume-modify ## [5.3.0] - 2017-12-01 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.15...v5.3.0 - Added a retry decorator. currently only used in setTags for VSI creation, which should allos VSI creation to be a bit more robust. - Updated unit tests to work with pytest3.3 ## [5.2.15] - 2017-10-30 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.14...v5.2.15 - Added dedicated host info to virt detail - #885 - Fixed createObjects on the rest api endpoint - changed securityGroups to use createObject instead of createObjects - Always set the endpoint_url by defaulting to the public URL if the endpoint type cannot be determined. - resource metadata update ## [5.2.14] - 2017-09-13 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.13...v5.2.14 - Improved slcli vs create-options output - Updated slcli vs create to support new virtual server public and dedicated host offerings ## [5.2.13] - 2017-09-05 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.12...v5.2.13 - Support for hourly billing of storage - Added exception handling for Managers.VSManager.wait_for_ready() - Added windows support for unit testing - Updated pypy version ## [5.2.12] - 2017-08-09 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.11...v5.2.12 - Support for storage_as_a_service block and file storage #### Added to CLI - block volume-count - file volume-count - securitygroups - create Create a security group. - delete Deletes the given security group - detail Get details about a security group. - edit Edit details of a security group. - interface-add Attach an interface to a security group. - interface-list List interfaces associated with security... - interface-remove Detach an interface from a security group. - list List security groups. - rule-add Add a security group rule to a security... - rule-edit Edit a security group rule in a security... - rule-list List security group rules. - rule-remove ## [5.2.11] - 2017-08-04 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.10...v5.2.11 - Sync VLAN and subnet detail CLI output ## [5.2.10] - 2017-07-27 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.9...v5.2.10 - Avoid blindly passing memory result to formatter ## [5.2.9] - 2017-07-27 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.8...v5.2.9 - Add support for dedicated host instances to virtual server upgrades #### Added to CLI * block volume-set-lun-id ## [5.2.8] - 2017-07-19 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.7...v5.2.8 * Resolved https://github.com/softlayer/softlayer-python/issues/835 * Resolved https://github.com/softlayer/softlayer-python/issues/826 * Fix dedicated/private VSI price retrieval for upgrades #### Added to CLI * block access-password ## [5.2.7] - 2017-06-22 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.6...v5.2.7 Adds support for duplicating block and file storage volumes. Only works on Storage as a Service volumes (Volumes that support encryption at rest). #### Added to CLI * [block|file] volume-duplicate ## [5.2.6] - 2017-05-22 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.5...v5.2.6 #### Added To CLI * ipsec list * ipsec detail * ipsec configure * ipsec update * ipsec subnet-add * ipsec subnet-remove * ipsec translation-add * ipsec translation-remove * ipsec translation-update ## [5.2.5] - 2017-05-05 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.1...v5.2.5 The SoftLayer_Network_Storage::storageTierLevel relational property changed in https://softlayer.github.io/release_notes/20170503/ , this version fixes problems caused by that. ### Changed - https://github.com/softlayer/softlayer-python/issues/818 - https://github.com/softlayer/softlayer-python/pull/817 ## [5.2.4] - 2017-04-06 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.3...v5.2.4 ### Changed Removed some debug code that was accidently added in the pypi release ## [5.2.3] - 2017-04-05 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.2...v5.2.3 ### Added - Adds Python 3.6 support ### Changed - CLI+API: Removes the iSCSI manager and commands - API: Fixes hardware order failing to find a single bare metal fast provision package to use ## [5.2.2] - 2017-02-24 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.1...v5.2.2 ### Added - Adds release process documentation - CLI: Displays NFS mount point for volumes in volume list and detail commands - CLI+API: Enables `slcli file` and `block` storage commands to order tier 10 endurance storage and replica ### Changed - Updates docs to replace `sl` command with `slcli` - CLI: Removes requirement to have `--os-type` provided for file storage ordering - API: Fixes block storage ordering to handle size provided properly - CLI: Fixes load balancer detail output so that JSON output is sane - API: Includes check if object storage endpoints were provided by the API before trying to add them to the endpoints returned by `list_endpoints` ## [5.2.1] - 2016-10-4 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.2.0...v5.2.1 ### Added - CLI: Adds a new 'jsonraw' format option that will print JSON without whitespace. This is useful for integrating the CLI with other tooling. ### Changed - API: Fixes JSON loading while using the REST transport with Python 3 - CLI+API: Metadata disks are now excluded when capturing "all" block devices with `slcli virtual capture --all` - CLI: Fixes a bug where dns zone importing was not importing wildcard records ## [5.2.0] - 2016-08-25 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.1.0...v5.2.0 ### Added - CLI+API: Significant additions to `slcli file` and `slcli block` commands. You can now authorize hosts, revoke access. You can also create, delete, restore, disable, enable snapshots. These features need to be battle-tested so report any issues that you see. - CLI+API: Adds logic to `SoftLayer.create_client_from_env` that detects if a REST endpoint_url was given in order to use the REST transport automatically. This means that you can also configure REST endpoints for `slcli`. The default still uses XML-RPC endpoint, but from a small amount of testing shows that the REST transport is significantly faster. - CLI: Adds `--network-space` to `slcli subnet list` in order to filter subnets based on network space. The two main options are PUBLIC and PRIVATE. For example, to list all public subnets, you can run: `slcli subnet list --network-space=PUBLIC` - CLI: Adds a new, non-default column, "created_by" that shows who ordered the volume for `slcli file volume-list` and `slcli block volume-list`. - CLI: Adds a new `slcli report bandwidth` command that will print a report of all bandwidth pools and virtual/hardware servers that your user has access to. - CLI: Adds an "IN" syntax to the `slcli call-api` command. For example, to find VSIs that are in either the dal05 or sng01 datacenter you can run this command: `slcli call-api Account getVirtualGuests -f 'virtualGuests.datacenter.name IN dal05,sng01'` ### Changed - CLI: Fixes a UnicodeEncodeError when piping slcli output with unicode characters. This was mostly reported with `slcli image list` but could also happen with many other calls. - CLI: Fixed a bug where os_version was not displaying correctly in `slcli virtual detail` or `slcli virtual detail` ## [5.1.0] - 2016-05-12 - Changes: https://github.com/softlayer/softlayer-python/compare/v5.0.1...v5.1.0 ### Added - CLI+API: Added block storage functionality. You can order, list, detail, cancel volumes. You can list and delete snapshots. You can also list ACLs for volumes. - Added functionality to attach/detach devices to tickets - CLI: Virtual list now lists users and passwords for all known software ### Changed - CLI: Fixes bug with `vlan detail` CLI command ## [5.0.1] - 2016-03-30 - https://github.com/softlayer/softlayer-python/compare/v5.0.0...v5.0.1 ### Changed - CLI: Adds missing dependency that was previously pulled in by prompt_toolkit - API: Fix a bug by updating the CDN manager to use the new purge method - CLI: Fixes bug that occured when iscsi listings with resources have no datacenter ## [5.0.0] - 2016-03-18 - Changes: https://github.com/softlayer/softlayer-python/compare/v4.1.1...v5.0.0 ### Added - CLI: Adds a shell (accessable with `slcli shell`) which provides autocomplete for slcli commands and options - CLI: How filters work with `slcli call-api` has changed significantly. Instead of accepting JSON, it now accepts an easier-to-use format. See `slcli call-api -h` for examples - API: Adds manager for object storage - API: Improved REST transport support ### Changed - CLI: Move modifying nic speed to `slcli virtual edit` and `slcli hardware edit` instead of having its own command - CLI: 'virtual' and 'hardware' are preferred over 'vs' and 'server' in the CLI - CLI+API: Many unmentioned bug fixes ## [4.1.1] - 2015-08-17 - Changes: https://github.com/softlayer/softlayer-python/compare/v4.1.0...v4.1.1 ### Added - CLI: Re-adds `--no-public` option to only provision private interfaces with servers via `slcli server create` ### Changed - CLI: Fixes to work with Click v5 - Removes non-functional `--vlan-public` and `--vlan-private` from `slcli server create` - VSManager.wait_for_ready will now behave as it is documented to behave. ## [4.1.0] - 2015-08-17 - Changes: https://github.com/softlayer/softlayer-python/compare/v4.0.4...v4.1.0 ### Added - CLI: Adds a shell which provides a shell interface for `slcli`. This is available by using `slcli shell` - CLI: `slcli vs create` and `slcli server create` will now prompt for missing required options - CLI+API: Adds editing of hardware tags ### Changed - CLI: Fixes `slcli firewall add` command - CLI: Handles case where `slcli vs detail` and `slcli server detail` was causing an error when trying to display the creator - API: Fixes VSManager.verify_create_instance() with tags (and, in turn, `slcli vs create --test` with tags) - CLI: Fixes `vs resume` command - API+CLI: Updates hardware ordering to deal with location-specific prices - CLI: Fixes several description errors in the CLI - CLI: Running `vs edit` without a tag option will no longer remove all tags ## [4.0.4] - 2015-06-30 - Changes: https://github.com/softlayer/softlayer-python/compare/v4.0.3...v4.0.4 ### Changed - CLI: Fixes bug with pulling the userData property for the virtual server detail - CLI: Fixes a class of bugs invloving unicode from the API ## [4.0.3] - 2015-06-15 - Changes: https://github.com/softlayer/softlayer-python/compare/v4.0.2...v4.0.3 ### Changed - CLI: Fixes bug with `slcli vs ready` command - CLI: Fixes bug with `slcli loadbal service-add` command - CLI: Fixes bug with `slcli vlan list` with vlans that don't have a datacenter - CLI: Improves validation of virtual server and hardware create commands ## [4.0.2] - 2015-05-04 - Changes https://github.com/softlayer/softlayer-python/compare/v4.0.1...v4.0.2 ### Changed - CLI: Fixes a bug that breaks user confirmation prompts - CLI: Fixes general issue with sorting on certain row types in the CLI - API: Fixes image capture for Windows guests ## [4.0.1] - 2015-04-28 - Changes: https://github.com/softlayer/softlayer-python/compare/v4.0.0...v4.0.1 ### Changed - CLI: Fixes bug in `sl setup` command not properly defaulting to current values. - API: Fixes bug where turning off compression headers would still send compression headers. - CLI: Reverts to using ids over global identifiers for `sl vs list` and `sl server list`. ## [4.0.0] - 2015-04-21 - Changes: https://github.com/softlayer/softlayer-python/compare/v3.3.0...v4.0.0 - Because there are many changes between version 3 and version 4, it is strongly recommend to pin the version of the SoftLayer python bindings as soon as you can in order to prevent unintentional breakage when upgrading. To keep yourself on version 3, you can use this directive: softlayer>=3,<4. That can be used with pip (pip install softlayer>=3,<4), requirements in your setup.py and/or in your requirements.txt file. ### Added - API: The client transport is now pluggable. If you want to add extra logging or accounting, you can now subclass or wrap softlayer.transports.XmlRpcTransport in order to do so. A good example of that is done with softlayer.transports.TimingTransport. - API+CLI: Adds ability to import virtual images from a given URI. The API only supports importing from a swift account using 'swift://'. For more details, see http://developer.softlayer.com/reference/services/SoftLayer_Virtual_Guest_Block_Device_Template_Group/createFromExternalSource. - CLI: A `--fixtures` global flag was added to pull from fixture data instead of the API. This is useful for discovery, demonstration and testing purposes. - CLI: A `--verbose` or `-v` flag was added to eventually replace `--debug`. To make a command more verbose, simply add more `-v` flags. For example `sl -vvv vs list` will be the most verbose and show everything down to request/response tracing. - CLI: Credentials can now be requested using `sl vs credentials `, `sl hardware credentials ` and `sl nas credentials ` for virtual servers, hardware servers and NAS accounts respectively. - CLI: Adds virtual server rescue command, `sl vs rescue ` ### Changed - CLI: The command is renamed from `sl` to `slcli` to avoid package conflicts. - CLI: Global options now need to be specified right after the `slcli` command. For example, you would now use `slcli --format=raw list` over `slcli vs list --format=raw`. This is a change for the following options: - --format - -c or --config - --debug - --proxy - -y or --really - --version - API: The hardware manager has a significant update to how place_order() works. It will now only support the fast server provisioning package which has presets for options like CPU, Memory and disk. - API: Removed deprecated SoftLayer.CCIManager. - API: Adds virtual server rescue command to SoftLayer.VSManager - CLI: Significant changes were done to the CLI argument parsing. Docopt was dropped in favor of click. Therefore, some subtle differences which aren't documented here may exist. ## [3.3.0] - 2014-10-23 - Changes: https://github.com/softlayer/softlayer-python/compare/v3.2.0...v3.3.0 ### Added - CLI+API: Load balancer support - CLI: More detail added to the `sl image detail` and `sl image list` commands - CLI: Adds command to import DNS entries from BIND zone files - CLI+API: Adds support for booting into rescue images for virtual servers and hardware - API: Adds ability to order virtual and hardare servers from a quote to the ordering manager ### Changed - CLI: Fixes bug with `sl server list-chassis` and `sl server list-chassis` - API: Restructure of the way custom authentication can be plugged in the API client - Several other bug fixes ## [3.2.0] - 2014-07-09 - Changes: https://github.com/softlayer/softlayer-python/compare/v3.1.0...v3.2.0 ### Added - CLI+API: Added firewall manager and CLI module - CLI+API: Added iscsi manager and CLI module - API: Added ability to create multiple virtual servers at once to VSManager - API: Added OrderingManager. Remove hard-coded price IDs ### Changed - Fixed several small bugs ## [3.1.0] - 2014-04-24 - Changes: https://github.com/softlayer/softlayer-python/compare/v3.0.2...v3.1.0 ### Added - CLI+API: Added CDN manager and CLI module - CLI+API: Added ticket manager and CLI module - CLI+API: Added image manager and improves image CLI module - CLI+API: Added the ability to specify a proxy URL for API bindings and the CLI - CLI+API: Added ability to resize a virtual machine - CLI+API: Added firewall manager and CLI module - CLI+API: Added load balancer manager and CLI module ### Changed - API: six is now used to provide support for Python 2 and Python 3 with the same source - CLI+API: Implemented product name changes in accordance with SoftLayer's new product names. Existing managers should continue to work as before. Minor CLI changes were necessary. - Many bug fixes and minor suggested improvements ## [3.0.2] - 2013-12-9 - Changes: https://github.com/softlayer/softlayer-python/compare/v3.0.1...v3.0.2 ### Added - CLI+API: Simplified object mask reformatting and added support for more complex masks. - CLI+API: Added IPMI IP address to hardware details. - CLI: Added support for ordering multiple disks when creating a CCI. - API: Added flag to disable compression on HTTP requests. - CLI: Added CIDR information to subnet displays. ### Changed - CLI: Fixed the sl bmc create --network argument. - CLI+API: Improved output of the message queue feature and fixed some minor bugs. - CLI: Fixed an error when using --test and ordering a non-private subnet. - API: Fix to prevent double counting results in summary_by_datacenter(). ### [3.0.1] - 2013-10-11 - Changes: https://github.com/softlayer/softlayer-python/compare/v3.0.0...v3.0.1 ### Added - CLI+API: Added ability to specify SSH keys when reloading CCIs and servers. ### Changed - CLI: Fixed an error message about pricing information that appeared when ordering a new private subnet. ## [3.0.0] - 2013-09-19 - Changes: https://github.com/softlayer/softlayer-python/compare/v2.3.0...v3.0.0 ### Added - CLI+API: Adds SoftLayer Message Queue Service bindings (as a manager) and a CLI counterpart. With this you can interact with existing message queue accounts - CLI+API: Adds the ability to create CCIs with the following options: metadata, post-install script, SSH key - CLI+API: Improved dedicated server ordering. Adds power management for hardware servers: power-on, power-off, power-cycle, reboot - CLI+API: Adds a networking manager and adds several network-related CLI modules. This includes the ability to: - list, create, cancel and assign global IPs - list, create, cancel and detail subnets. Also has the ability to lookup details about an IP address with 'sl subnet lookup' - list, detail VLANs - show and edit RWhois data - CLI+API: Ability to manage SSH Keys with a manager and a CLI module - CLI: Adds a --debug option to print out debugging information. --debug=3 is the highest log level which prints full HTTP request/responses including the body - CLI+API: Adds the ability to create hardware servers with a default SSH key - CLI: Adds templating for creating CCIs and hardware nodes which can be used to create more CCIs and hardware with the same settings ### Changed - Many bug fixes and consistency improvements - API: Removes old API client interfaces which have been deprecated in the v2. See link for more details: https://softlayer-api-python-client.readthedocs.org/en/latest/api/client/#backwards-compatibility - CLI: The commands in the main help are now organized into categories ## [2.3.0] - 2013-07-19 - Changes: https://github.com/softlayer/softlayer-python/compare/v2.2.0...v2.3.0 ### Added - CLI+API: Added much more hardware support: Filters for hardware listing, dedicated server/bare metal cloud ordering, hardware cancellation - CLI+API: Added DNS Zone filtering (server side) - CLI+API: Added Post Install script support for CCIs and hardware - CLI: Added Message queue functionality - CLI: Added --debug option to CLI commands - API: Added more logging - API: Added token-based auth so you can use the API bindings with your username/password if you want. (It's still highly recommended to use your API key instead of your password) ### Changed - Several bug fixes and improvements - Removed Python 2.5 support. Some stuff MIGHT work with 2.5 but it is no longer tested - API: Refactored managers into their own module to not clutter the top level ## [2.2.0] - 2013-04-11 ### Added - Added sphinx documentation. See it here: https://softlayer-api-python-client.readthedocs.org - CCI: Adds Support for Additional Disks - CCI: Adds a way to block until transactions are done on a CCI - CLI: For most CCI commands, you can specify id, hostname, private ip or public ip as - CLI: Adds the ability to filter list results for CCIs - API: for large result sets, requests can now be chunked into smaller batches on the server side. Using service.iter_call('getObjects', ...) or service.getObjects(..., iter=True) will return a generator regardless of the results returned. offset and limit can be passed in like normal. An additional named parameter of 'chunk' is used to limit the number of items coming back in a single request, defaults to 100 ### Changed - Consistency changes/bug fixes softlayer-python-6.1.4/CONTRIBUTING.md000066400000000000000000000146411437054676600173320ustar00rootroot00000000000000# Contributing to softlayer-python We are happy to accept contributions to softlayer-python. Please follow the guidelines below. ## Procedural 1. All code changes require a corresponding issue. [Open an issue here](https://github.com/softlayer/softlayer-python/issues). 2. Fork the [softlayer-python](https://github.com/softlayer/softlayer-python) repository. 3. Make any changes required, commit messages should reference the issue number (include #1234 if the message if your issue is number 1234 for example). 4. Make a pull request from your fork/branch to origin/master 5. Requires 1 approval for merging * Additional infomration can be found in our [contribution guide](http://softlayer-python.readthedocs.org/en/latest/dev/index.html) ## Legal * See our [Contributor License Agreement](./docs/dev/cla-individual.md). Opening a pull request is acceptance of this agreement. * If you're contributing on behalf of your employer we'll need a signed copy of our corporate contributor agreement (CCLA) as well. You can find the [CCLA here](./docs/dev/cla-corporate.md). ## Code style Code is tested and style checked with tox, you can run the tox tests individually by doing `tox -e ` * `autopep8 -r -v -i --max-line-length 119 SoftLayer/` * `autopep8 -r -v -i --max-line-length 119 tests/` * `tox -e analysis` * `tox -e py36` * `git commit --message="# ` * `git push origin ` * create pull request ## Documentation CLI command should have a more human readable style of documentation. Manager methods should have a decent docblock describing any parameters and what the method does. Docs are generated with [Sphinx](https://docs.readthedocs.io/en/latest/intro/getting-started-with-sphinx.html) and once Sphinx is setup, you can simply do `make html` in the softlayer-python/docs directory, which should generate the HTML in `softlayer-python/docs/_build/html` for testing. ## Unit Tests All new features should be 100% code covered, and your pull request should at the very least increase total code overage. ### Mocks To tests results from the API, we keep mock results in SoftLayer/fixtures// with the method name matching the variable name. Any call to a service that doesn't have a fixture will result in a TransportError ### Overriding Fixtures Adding your expected output in the fixtures file with a unique name is a good way to define a fixture that gets used frequently in a test. ```python from SoftLayer.fixtures import SoftLayer_Product_Package def test_test(self): amock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') amock.return_value = fixtures.SoftLayer_Product_Package.RESERVED_CAPACITY ``` Otherwise defining it on the spot works too. ```python def test_test(self): mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') mock.return_value = { 'billingItem': {'hourlyFlag': True, 'id': 449}, } ``` ### Call testing Testing your code to make sure it makes the correct API call is also very important. The testing.TestCase class has a method call `assert_called_with` which is pretty handy here. ```python self.assert_called_with( 'SoftLayer_Billing_Item', # Service 'cancelItem', # Method args=(True, True, ''), # Args identifier=449, # Id mask=mock.ANY, # object Mask, filter=mock.ANY, # object Filter limit=0, # result Limit offset=0 # result Offset ) ``` Making sure a API was NOT called ```python self.assertEqual([], self.calls('SoftLayer_Account', 'getObject')) ``` Making sure an API call has a specific arg, but you don't want to list out the entire API call (like with a place order test) ```python # Get the API Call signature order_call = self.calls('SoftLayer_Product_Order', 'placeOrder') # Get the args property of that API call, which is a tuple, with the first entry being our data. order_args = getattr(order_call[0], 'args')[0] # Test our specific argument value self.assertEqual(123, order_args['hostId']) ``` ## Project Management ### Issues * _Title_: Should contain quick highlight of the issue is about * _Body_: All the technical information goes here * _Assignee_: Should be the person who is actively working on an issue. * _Label_: All issues should have at least 1 Label. * _Projects_: Should be added to the quarerly Softlayer project when being worked on * _Milestones_: Not really used, can be left blank * _Linked Pull Request_: Should be linked to the relavent pull request when it is opened. ### Pull Requests * _Title_: Should be similar to the title of the issue it is fixing, or otherwise descibe what is chaning in the pull request * _Body_: Should have "Fixes #1234" at least, with some notes about the specific pull request if needed. Most technical information should still be in the github issue. * _Reviewers_: 1 Reviewer is required * _Assignee_: Should be the person who opened the pull request * _Labels_: Should match the issue * _Projects_: Should match the issue * _Milestones_: Not really used, can be left blank * _Linked issues_: If you put "Fixes #" in the body, this should be automatically filled in, otherwise link manually. ### Code Reviews All issues should be reviewed by at least 1 member of the SLDN team that is not the person opening the pull request. Time permitting, all members of the SLDN team should review the request. #### Things to look for while doing a review As a reviewer, these are some guidelines when doing a review, but not hard rules. * Code Style: Generally `tox -e analysis` will pick up most style violations, but anything that is wildly different from the normal code patters in this project should be changed to match, unless there is a strong reason to not do so. * API Calls: Close attention should be made to any new API calls, to make sure they will work as expected, and errors are handled if needed. * DocBlock comments: CLI and manager methods need to be documented well enough for users to easily understand what they do. * Easy to read code: Code should generally be easy enough to understand at a glance. Confusing code is a sign that it should either be better documented, or refactored a bit to be clearer in design. ### Testing When doing testing of a code change, indicate this with a comment on the pull request like :heavy_check: `slcli vs list --new-feature` :x: `slcli vs list --broken-feature` softlayer-python-6.1.4/CONTRIBUTORS000066400000000000000000000024071437054676600167560ustar00rootroot00000000000000Amol Jadhav Aparna Patil Boden Russell Brian Cline chechuironman Christopher Gallo David Ibarra Hans Kristian Moen Ian Sutton Jake Williams Jason Johnson Kevin Landreth Kevin McDonald Łukasz Oleś Michael Fork Nathan Beittenmiller Neetu Jain Paul Sroufe Phil Jackson Robert Chumbley Ryan Hanson Scott Thompson Sergio Carlos Shane Poage Shravan Kumar Raghu simplydave SoftLayer suppandi Swapnil Khanapurkar The SoftLayer Developer Network Tim Ariyeh Wissam Elriachy Anthony Monthe (ZuluPro) softlayer-python-6.1.4/ISSUE_TEMPLATE000066400000000000000000000004451437054676600172040ustar00rootroot00000000000000**Please triple-check to make sure that you have properly masked out user credentials like usernames, passwords and API keys before submitting your issue** ### Expected Behavior ### Actual Behavior ### Environment Information Operating System: softlayer-python version (`slcli --version`): softlayer-python-6.1.4/LICENSE000066400000000000000000000021051437054676600160760ustar00rootroot00000000000000Copyright (c) 2016 SoftLayer Technologies, Inc. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. softlayer-python-6.1.4/MANIFEST.in000066400000000000000000000000431437054676600166260ustar00rootroot00000000000000include LICENSE include README.rst softlayer-python-6.1.4/Makefile000066400000000000000000000164421437054676600165420ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/softlayer-python.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/softlayer-python.qhc" applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/softlayer-python" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/softlayer-python" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." softlayer-python-6.1.4/README-snapcraft.md000066400000000000000000000010411437054676600203250ustar00rootroot00000000000000# To Install: `sudo snap install slcli` ------------------------------------------------------------------------ # What are SNAPS? Snaps are available for any Linux OS running snapd, the service that runs and manage snaps. For more info, see: https://snapcraft.io/ or to learn to build and publish your own snaps, please see: https://docs.snapcraft.io/build-snaps/languages?_ga=2.49470950.193172077.1519771181-1009549731.1511399964 # Releasing Builds should be automagic here. https://build.snapcraft.io/user/softlayer/softlayer-python softlayer-python-6.1.4/README.rst000066400000000000000000000144311437054676600165650ustar00rootroot00000000000000SoftLayer API Python Client =========================== .. image:: https://github.com/softlayer/softlayer-python/workflows/Tests/badge.svg :target: https://github.com/softlayer/softlayer-python/actions?query=workflow%3ATests .. image:: https://github.com/softlayer/softlayer-python/workflows/documentation/badge.svg :target: https://github.com/softlayer/softlayer-python/actions?query=workflow%3Adocumentation .. image:: https://landscape.io/github/softlayer/softlayer-python/master/landscape.svg :target: https://landscape.io/github/softlayer/softlayer-python/master .. image:: https://badge.fury.io/py/SoftLayer.svg :target: http://badge.fury.io/py/SoftLayer .. image:: https://coveralls.io/repos/github/softlayer/softlayer-python/badge.svg?branch=master :target: https://coveralls.io/github/softlayer/softlayer-python?branch=master .. image:: https://snapcraft.io//slcli/badge.svg :target: https://snapcraft.io/slcli This library provides a simple Python client to interact with `SoftLayer's XML-RPC API `_. A command-line interface is also included and can be used to manage various SoftLayer products and services. Documentation ------------- Documentation for the Python client is available at `Read the Docs `_ . Additional API documentation can be found on the SoftLayer Development Network: * `SoftLayer API reference `_ * `Object mask information and examples `_ * `Code Examples `_ Installation ------------ Install via pip: .. code-block:: bash $ pip install softlayer Or you can install from source. Download source and run: .. code-block:: bash $ python setup.py install Another (safer) method of installation is to use the published snap. Snaps are available for any Linux OS running snapd, the service that runs and manage snaps. Snaps are "auto-updating" packages and will not disrupt the current versions of libraries and software packages on your Linux-based system. To learn more, please visit: https://snapcraft.io/ To install the slcli snap: .. code-block:: bash $ sudo snap install slcli (or to get the latest release) $ sudo snap install slcli --edge The most up-to-date version of this library can be found on the SoftLayer GitHub public repositories at http://github.com/softlayer. For questions regarding the use of this library please post to Stack Overflow at https://stackoverflow.com/ and your posts with “SoftLayer” so our team can easily find your post. To report a bug with this library please create an Issue on github. InsecurePlatformWarning Notice ------------------------------ This library relies on the `requests `_ library to make HTTP requests. On Python versions below Python 2.7.9, requests has started emitting a security warning (InsecurePlatformWarning) due to insecurities with creating SSL connections. To resolve this, upgrade to Python 2.7.9+ or follow the instructions here: http://stackoverflow.com/a/29099439. Basic Usage ----------- - `The Complete Command Directory `_ Advanced Usage -------------- You can automatically set some parameters via environment variables with by using the SLCLI prefix. For example .. code-block:: bash $ export SLCLI_VERBOSE=3 $ export SLCLI_FORMAT=json $ slcli vs list is equivalent to .. code-block:: bash $ slcli -vvv --format=json vs list Getting Help ------------ Bugs and feature requests about this library should have a `GitHub issue `_ opened about them. Issues with the Softlayer API itself should be addressed by opening a ticket. Examples -------- A curated list of examples on how to use this library can be found at `SLDN `_ Debugging --------- To get the exact API call that this library makes, you can do the following. For the CLI, just use the -vvv option. If you are using the REST endpoint, this will print out a curl command that you can use, if using XML, this will print the minimal python code to make the request without the softlayer library. .. code-block:: bash $ slcli -vvv vs list If you are using the library directly in python, you can do something like this. .. code-block:: python import SoftLayer import logging class invoices(): def __init__(self): self.client = SoftLayer.Client() debugger = SoftLayer.DebugTransport(self.client.transport) self.client.transport = debugger def main(self): mask = "mask[id]" account = self.client.call('Account', 'getObject', mask=mask); print("AccountID: %s" % account['id']) def debug(self): for call in self.client.transport.get_last_calls(): print(self.client.transport.print_reproduceable(call)) if __name__ == "__main__": main = example() main.main() main.debug() System Requirements ------------------- * Python 3.8, 3.9, or 3.10. * A valid SoftLayer API username and key. * A connection to SoftLayer's private network is required to use our private network API endpoints. Python 3.6 Support ------------------ As of version 6.0.0 SoftLayer-Python will no longer support python3.6, which is `End of Life as of 2022 `_. If you cannot install python 3.8+ for some reason, you will need to use a version of softlayer-python <= 6.0.0 Python 2.7 Support ------------------ As of version 5.8.0 SoftLayer-Python will no longer support python2.7, which is `End Of Life as of 2020 `_ . If you cannot install python 3.6+ for some reason, you will need to use a version of softlayer-python <= 5.7.2 Python Packages --------------- * prettytable >= 2.5.0 * click >= 8.0.4 * requests >= 2.20.0 * prompt_toolkit >= 2 * pygments >= 2.0.0 * urllib3 >= 1.24 * rich == 12.3.0 *NOTE* If `ptable` (not prettytable) is installed, this will cause issues rendering tables. Copyright --------- This software is Copyright (c) 2016-2021 SoftLayer Technologies, Inc. See the bundled LICENSE file for more information. softlayer-python-6.1.4/RELEASE.md000066400000000000000000000054261437054676600165040ustar00rootroot00000000000000 # Versions This project follows the Major.Minor.Revision versioning system. Fixes, and minor additions would increment Revision. Large changes and additions would increment Minor, and anything that would be a "Breaking" change, or redesign would be an increment of Major. # Changelog When doing a release, the Changelog format should be as follows: ```markdown ## [Version] - YYYY-MM-DD https://github.com/softlayer/softlayer-python/compare/v5.9.0...v5.9.1 #### New Command - `slcli new command` #issueNumber #### Improvements - List out improvements #issueNumber - Something else that changed #issueNumber #### Deprecated - List something that got removed #issueNumber ``` # Normal Release steps A "release" of the softlayer-python project is the current state of the `master` branch. Any changes in the master branch should be considered releaseable. 1. Create the changelog entry, us this to update `CHANGELOG.md` and as the text for the release on github. 2. Update the version numbers in these files on the master branch. - `SoftLayer/consts.py` - `setup.py` 3. Make sure the tests for the build all pass 4. [Draft a new release](https://github.com/softlayer/softlayer-python/releases/new) - Version should start with `v` followed by Major.Minor.Revision: `vM.m.r` - Title should be `M.m.r` - Description should be the release notes - Target should be the `master` branch 5. The github automation should take care of publishing the release to [PyPi](https://pypi.org/project/SoftLayer/). This may take a few minutes to update. # Manual Release steps 1. Create the changelog entry, us this to update `CHANGELOG.md` and as the text for the release on github. 2. Update the version numbers in these files on the master branch. - `SoftLayer/consts.py` - `setup.py` 3. Commit your changes to `master`, and make sure `softlayer/softlayer-python` repo is updated to reflect that 4. Make sure your `upstream` repo is set ``` git remote -v upstream git@github.com:softlayer/softlayer-python.git (fetch) upstream git@github.com:softlayer/softlayer-python.git (push) ``` 5. Create and publish the package - Make sure you have `twine` installed, this is what uploads the pacakge to PyPi. - Before you do this, make sure you have the organization repository set up as upstream remote, also make sure that you have pip set up with your PyPi user credentials. The easiest way to do that is to create a file at `~/.pypirc` with the following contents: ``` [server-login] username:YOUR_USERNAME password:YOUR_PASSWORD ``` - Run `python fabfile.py 5.7.2`. Where `5.7.2` is the `M.m.r` version number. Don't use the `v` here in the version number. *NOTE* PyPi doesn't let you reupload a version, if you upload a bad package for some reason, you have to create a new version. softlayer-python-6.1.4/SECURITY.md000066400000000000000000000010721437054676600166640ustar00rootroot00000000000000# Security Policy ## Supported Versions Generally only the latest release will be actively worked on and supported. Version 5.7.2 is the last version that supports python2.7. | Version | Supported | | ------- | ------------------ | | 5.9.x | :white_check_mark: | | 5.7.2 | :white_check_mark: | | < 5.7.2 | :x: | ## Reporting a Vulnerability Create a new [Bug Report](https://github.com/softlayer/softlayer-python/issues/new?assignees=&labels=Bug&template=bug_report.md&title=) to let us know about any vulnerabilities in the code base. softlayer-python-6.1.4/SoftLayer/000077500000000000000000000000001437054676600170035ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/API.py000066400000000000000000000546161437054676600200020ustar00rootroot00000000000000""" SoftLayer.API ~~~~~~~~~~~~~ SoftLayer API bindings :license: MIT, see LICENSE for more details. """ # pylint: disable=invalid-name import time import warnings import json import logging import requests from SoftLayer import auth as slauth from SoftLayer import config from SoftLayer import consts from SoftLayer import exceptions from SoftLayer import transports LOGGER = logging.getLogger(__name__) API_PUBLIC_ENDPOINT = consts.API_PUBLIC_ENDPOINT API_PRIVATE_ENDPOINT = consts.API_PRIVATE_ENDPOINT CONFIG_FILE = consts.CONFIG_FILE __all__ = [ 'create_client_from_env', 'Client', 'BaseClient', 'API_PUBLIC_ENDPOINT', 'API_PRIVATE_ENDPOINT', 'IAMClient', ] VALID_CALL_ARGS = set(( 'id', 'mask', 'filter', 'headers', 'compress', 'raw_headers', 'limit', 'offset', 'verify', )) def create_client_from_env(username=None, api_key=None, endpoint_url=None, timeout=None, auth=None, config_file=None, proxy=None, user_agent=None, transport=None, verify=True): """Creates a SoftLayer API client using your environment. Settings are loaded via keyword arguments, environemtal variables and config file. :param username: an optional API username if you wish to bypass the package's built-in username :param api_key: an optional API key if you wish to bypass the package's built in API key :param endpoint_url: the API endpoint base URL you wish to connect to. Set this to API_PRIVATE_ENDPOINT to connect via SoftLayer's private network. :param proxy: proxy to be used to make API calls :param integer timeout: timeout for API requests :param auth: an object which responds to get_headers() to be inserted into the xml-rpc headers. Example: `BasicAuthentication` :param config_file: A path to a configuration file used to load settings :param user_agent: an optional User Agent to report when making API calls if you wish to bypass the packages built in User Agent string :param transport: An object that's callable with this signature: transport(SoftLayer.transports.Request) :param bool verify: decide to verify the server's SSL/TLS cert. DO NOT SET TO FALSE WITHOUT UNDERSTANDING THE IMPLICATIONS. Usage: >>> import SoftLayer >>> client = SoftLayer.create_client_from_env() >>> resp = client.call('Account', 'getObject') >>> resp['companyName'] 'Your Company' """ if config_file is None: config_file = CONFIG_FILE settings = config.get_client_settings(username=username, api_key=api_key, endpoint_url=endpoint_url, timeout=timeout, proxy=proxy, verify=verify, config_file=config_file) if transport is None: url = settings.get('endpoint_url') if url is not None and '/rest' in url: # If this looks like a rest endpoint, use the rest transport transport = transports.RestTransport( endpoint_url=settings.get('endpoint_url'), proxy=settings.get('proxy'), timeout=settings.get('timeout'), user_agent=user_agent, verify=verify, ) else: # Default the transport to use XMLRPC transport = transports.XmlRpcTransport( endpoint_url=settings.get('endpoint_url'), proxy=settings.get('proxy'), timeout=settings.get('timeout'), user_agent=user_agent, verify=verify, ) # If we have enough information to make an auth driver, let's do it if auth is None and settings.get('username') and settings.get('api_key'): # NOTE(kmcdonald): some transports mask other transports, so this is # a way to find the 'real' one real_transport = getattr(transport, 'transport', transport) if isinstance(real_transport, transports.XmlRpcTransport): auth = slauth.BasicAuthentication( settings.get('username'), settings.get('api_key'), ) elif isinstance(real_transport, transports.RestTransport): auth = slauth.BasicHTTPAuthentication( settings.get('username'), settings.get('api_key'), ) return BaseClient(auth=auth, transport=transport, config_file=config_file) def Client(**kwargs): """Get a SoftLayer API Client using environmental settings. Deprecated in favor of create_client_from_env() """ warnings.warn("use SoftLayer.create_client_from_env() instead", DeprecationWarning) return create_client_from_env(**kwargs) class BaseClient(object): """Base SoftLayer API client. :param auth: auth driver that looks like SoftLayer.auth.AuthenticationBase :param transport: An object that's callable with this signature: transport(SoftLayer.transports.Request) """ _prefix = "SoftLayer_" def __init__(self, auth=None, transport=None, config_file=None): if config_file is None: config_file = CONFIG_FILE self.auth = auth self.config_file = config_file self.settings = config.get_config(self.config_file) if transport is None: url = self.settings['softlayer'].get('endpoint_url') if url is not None and '/rest' in url: # If this looks like a rest endpoint, use the rest transport transport = transports.RestTransport( endpoint_url=url, proxy=self.settings['softlayer'].get('proxy'), # prevents an exception incase timeout is a float number. timeout=int(self.settings['softlayer'].getfloat('timeout')), user_agent=consts.USER_AGENT, verify=self.settings['softlayer'].getboolean('verify'), ) else: # Default the transport to use XMLRPC transport = transports.XmlRpcTransport( endpoint_url=url, proxy=self.settings['softlayer'].get('proxy'), timeout=int(self.settings['softlayer'].getfloat('timeout')), user_agent=consts.USER_AGENT, verify=self.settings['softlayer'].getboolean('verify'), ) self.transport = transport def authenticate_with_password(self, username, password, security_question_id=None, security_question_answer=None): """Performs Username/Password Authentication :param string username: your SoftLayer username :param string password: your SoftLayer password :param int security_question_id: The security question id to answer :param string security_question_answer: The answer to the security question """ self.auth = None res = self.call('User_Customer', 'getPortalLoginToken', username, password, security_question_id, security_question_answer) self.auth = slauth.TokenAuthentication(res['userId'], res['hash']) return res['userId'], res['hash'] def __getitem__(self, name): """Get a SoftLayer Service. :param name: The name of the service. E.G. Account Usage: >>> import SoftLayer >>> client = SoftLayer.create_client_from_env() >>> client['Account'] """ return Service(self, name) def call(self, service, method, *args, **kwargs): """Make a SoftLayer API call. :param method: the method to call on the service :param \\*args: (optional) arguments for the remote call :param id: (optional) id for the resource :param mask: (optional) object mask :param dict filter: (optional) filter dict :param dict headers: (optional) optional XML-RPC headers :param boolean compress: (optional) Enable/Disable HTTP compression :param dict raw_headers: (optional) HTTP transport headers :param int limit: (optional) return at most this many results :param int offset: (optional) offset results by this many :param boolean iter: (optional) if True, returns a generator with the results :param bool verify: verify SSL cert :param cert: client certificate path Usage: >>> import SoftLayer >>> client = SoftLayer.create_client_from_env() >>> client.call('Account', 'getVirtualGuests', mask="id", limit=10) [...] """ if kwargs.pop('iter', False): # Most of the codebase assumes a non-generator will be returned, so casting to list # keeps those sections working return list(self.iter_call(service, method, *args, **kwargs)) invalid_kwargs = set(kwargs.keys()) - VALID_CALL_ARGS if invalid_kwargs: raise TypeError( 'Invalid keyword arguments: %s' % ','.join(invalid_kwargs)) prefixes = (self._prefix, 'BluePages_Search', 'IntegratedOfferingTeam_Region') if self._prefix and not service.startswith(prefixes): service = self._prefix + service http_headers = {'Accept': '*/*'} if kwargs.get('compress', True): http_headers['Accept-Encoding'] = 'gzip, deflate, compress' else: http_headers['Accept-Encoding'] = None if kwargs.get('raw_headers'): http_headers.update(kwargs.get('raw_headers')) request = transports.Request() request.service = service request.method = method request.args = args request.transport_headers = http_headers request.identifier = kwargs.get('id') request.mask = kwargs.get('mask') request.filter = kwargs.get('filter') request.limit = kwargs.get('limit') request.offset = kwargs.get('offset') if kwargs.get('verify') is not None: request.verify = kwargs.get('verify') if self.auth: extra_headers = self.auth.get_headers() if extra_headers: warnings.warn("auth.get_headers() is deprecated and will be " "removed in the next major version", DeprecationWarning) request.headers.update(extra_headers) request = self.auth.get_request(request) request.headers.update(kwargs.get('headers', {})) return self.transport(request) __call__ = call def iter_call(self, service, method, *args, **kwargs): """A generator that deals with paginating through results. :param service: the name of the SoftLayer API service :param method: the method to call on the service :param integer limit: result size for each API call (defaults to 100) :param \\*args: same optional arguments that ``Service.call`` takes :param \\*\\*kwargs: same optional keyword arguments that ``Service.call`` takes """ limit = kwargs.pop('limit', 100) offset = kwargs.pop('offset', 0) if limit <= 0: raise AttributeError("Limit size should be greater than zero.") # Set to make unit tests, which call this function directly, play nice. kwargs['iter'] = False result_count = 0 keep_looping = True while keep_looping: # Get the next results results = self.call(service, method, offset=offset, limit=limit, *args, **kwargs) # Apparently this method doesn't return a list. # Why are you even iterating over this? if not isinstance(results, transports.SoftLayerListResult): if isinstance(results, list): # Close enough, this makes testing a lot easier results = transports.SoftLayerListResult(results, len(results)) else: yield results return for item in results: yield item result_count += 1 # Got less results than requested, we are at the end if len(results) < limit: keep_looping = False # Got all the needed items if result_count >= results.total_count: keep_looping = False offset += limit def __repr__(self): return "Client(transport=%r, auth=%r)" % (self.transport, self.auth) __str__ = __repr__ def __len__(self): return 0 class IAMClient(BaseClient): """IBM ID Client for using IAM authentication :param auth: auth driver that looks like SoftLayer.auth.AuthenticationBase :param transport: An object that's callable with this signature: transport(SoftLayer.transports.Request) """ def authenticate_with_password(self, username, password, security_question_id=None, security_question_answer=None): """Performs IBM IAM Username/Password Authentication :param string username: your IBMid username :param string password: your IBMid password """ iam_client = requests.Session() headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': consts.USER_AGENT, 'Accept': 'application/json' } data = { 'grant_type': 'password', 'password': password, 'response_type': 'cloud_iam', 'username': username } try: response = iam_client.request( 'POST', 'https://iam.cloud.ibm.com/identity/token', data=data, headers=headers, auth=requests.auth.HTTPBasicAuth('bx', 'bx') ) if response.status_code != 200: LOGGER.error("Unable to login: %s", response.text) response.raise_for_status() tokens = json.loads(response.text) except requests.HTTPError as ex: error = json.loads(response.text) raise exceptions.IAMError(response.status_code, error.get('errorMessage'), 'https://iam.cloud.ibm.com/identity/token') from ex self.settings['softlayer']['access_token'] = tokens['access_token'] self.settings['softlayer']['refresh_token'] = tokens['refresh_token'] config.write_config(self.settings, self.config_file) self.auth = slauth.BearerAuthentication('', tokens['access_token'], tokens['refresh_token']) return tokens def authenticate_with_passcode(self, passcode): """Performs IBM IAM SSO Authentication :param string passcode: your IBMid password """ iam_client = requests.Session() headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': consts.USER_AGENT, 'Accept': 'application/json' } data = { 'grant_type': 'urn:ibm:params:oauth:grant-type:passcode', 'passcode': passcode, 'response_type': 'cloud_iam' } try: response = iam_client.request( 'POST', 'https://iam.cloud.ibm.com/identity/token', data=data, headers=headers, auth=requests.auth.HTTPBasicAuth('bx', 'bx') ) if response.status_code != 200: LOGGER.error("Unable to login: %s", response.text) response.raise_for_status() tokens = json.loads(response.text) except requests.HTTPError as ex: error = json.loads(response.text) raise exceptions.IAMError(response.status_code, error.get('errorMessage'), 'https://iam.cloud.ibm.com/identity/token') from ex self.settings['softlayer']['access_token'] = tokens['access_token'] self.settings['softlayer']['refresh_token'] = tokens['refresh_token'] a_expire = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(tokens['expiration'])) r_expire = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(tokens['refresh_token_expiration'])) LOGGER.warning("Tokens retrieved, expires at %s, Refresh expires at %s", a_expire, r_expire) config.write_config(self.settings, self.config_file) self.auth = slauth.BearerAuthentication('', tokens['access_token'], tokens['refresh_token']) return tokens def authenticate_with_iam_token(self, a_token, r_token=None): """Authenticates to the SL API with an IAM Token :param string a_token: Access token :param string r_token: Refresh Token, to be used if Access token is expired. """ self.auth = slauth.BearerAuthentication('', a_token, r_token) def refresh_iam_token(self, r_token, account_id=None, ims_account=None): """Refreshes the IAM Token, will default to values in the config file""" iam_client = requests.Session() headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': consts.USER_AGENT, 'Accept': 'application/json' } data = { 'grant_type': 'refresh_token', 'refresh_token': r_token, 'response_type': 'cloud_iam' } sl_config = self.settings['softlayer'] if account_id is None and sl_config.get('account_id', False): account_id = sl_config.get('account_id') if ims_account is None and sl_config.get('ims_account', False): ims_account = sl_config.get('ims_account') data['account'] = account_id data['ims_account'] = ims_account try: response = iam_client.request( 'POST', 'https://iam.cloud.ibm.com/identity/token', data=data, headers=headers, auth=requests.auth.HTTPBasicAuth('bx', 'bx') ) if response.status_code != 200: LOGGER.warning("Unable to refresh IAM Token. %s", response.text) response.raise_for_status() tokens = json.loads(response.text) except requests.HTTPError as ex: error = json.loads(response.text) raise exceptions.IAMError(response.status_code, error.get('errorMessage'), 'https://iam.cloud.ibm.com/identity/token') from ex a_expire = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(tokens['expiration'])) r_expire = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(tokens['refresh_token_expiration'])) LOGGER.warning("Tokens retrieved, expires at %s, Refresh expires at %s", a_expire, r_expire) self.settings['softlayer']['access_token'] = tokens['access_token'] self.settings['softlayer']['refresh_token'] = tokens['refresh_token'] config.write_config(self.settings, self.config_file) self.auth = slauth.BearerAuthentication('', tokens['access_token']) return tokens def call(self, service, method, *args, **kwargs): """Handles refreshing IAM tokens in case of a HTTP 401 error""" try: return super().call(service, method, *args, **kwargs) except exceptions.SoftLayerAPIError as ex: if ex.faultCode == 401: LOGGER.warning("Token has expired, trying to refresh. %s", ex.faultString) return ex else: raise ex def __repr__(self): return "IAMClient(transport=%r, auth=%r)" % (self.transport, self.auth) class Service(object): """A SoftLayer Service. :param client: A SoftLayer.API.Client instance :param name str: The service name """ def __init__(self, client, name): self.client = client self.name = name def call(self, name, *args, **kwargs): """Make a SoftLayer API call :param service: the name of the SoftLayer API service :param method: the method to call on the service :param \\*args: same optional arguments that ``BaseClient.call`` takes :param \\*\\*kwargs: same optional keyword arguments that ``BaseClient.call`` takes :param service: the name of the SoftLayer API service Usage: >>> import SoftLayer >>> client = SoftLayer.create_client_from_env() >>> client['Account'].getVirtualGuests(mask="id", limit=10) [...] """ return self.client.call(self.name, name, *args, **kwargs) __call__ = call def iter_call(self, name, *args, **kwargs): """A generator that deals with paginating through results. :param method: the method to call on the service :param integer chunk: result size for each API call :param \\*args: same optional arguments that ``Service.call`` takes :param \\*\\*kwargs: same optional keyword arguments that ``Service.call`` takes Usage: >>> import SoftLayer >>> client = SoftLayer.create_client_from_env() >>> gen = client.call('Account', 'getVirtualGuests', iter=True) >>> for virtual_guest in gen: ... virtual_guest['id'] ... 1234 4321 """ return self.client.iter_call(self.name, name, *args, **kwargs) def __getattr__(self, name): if name in ["__name__", "__bases__"]: raise AttributeError("'Obj' object has no attribute '%s'" % name) def call_handler(*args, **kwargs): " Handler that actually makes the API call " return self(name, *args, **kwargs) return call_handler def __repr__(self): return "" % (self.name,) __str__ = __repr__ softlayer-python-6.1.4/SoftLayer/CLI/000077500000000000000000000000001437054676600174125ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/CLI/__init__.py000066400000000000000000000003451437054676600215250ustar00rootroot00000000000000""" SoftLayer.CLI ~~~~~~~~~~~~~~ Contains all code related to the CLI interface :license: MIT, see LICENSE for more details. """ # pylint: disable=w0401, invalid-name from SoftLayer.CLI.helpers import * # NOQA softlayer-python-6.1.4/SoftLayer/CLI/account/000077500000000000000000000000001437054676600210465ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/CLI/account/__init__.py000066400000000000000000000000271437054676600231560ustar00rootroot00000000000000"""Account commands""" softlayer-python-6.1.4/SoftLayer/CLI/account/bandwidth_pools.py000066400000000000000000000026721437054676600246070ustar00rootroot00000000000000"""Displays information about the accounts bandwidth pools""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.account import AccountManager as AccountManager from SoftLayer import utils @click.command(cls=SLCommand, ) @environment.pass_env def cli(env): """Displays bandwidth pool information Similiar to https://cloud.ibm.com/classic/network/bandwidth/vdr """ manager = AccountManager(env.client) items = manager.get_bandwidth_pools() table = formatting.Table([ "Id", "Pool Name", "Region", "Servers", "Allocation", "Current Usage", "Projected Usage" ], title="Bandwidth Pools") table.align = 'l' for item in items: id_bandwidth = item.get('id') name = item.get('name') region = utils.lookup(item, 'locationGroup', 'name') servers = manager.get_bandwidth_pool_counts(identifier=item.get('id')) allocation = "{} GB".format(item.get('totalBandwidthAllocated', 0)) current = "{} GB".format(utils.lookup(item, 'billingCyclePublicBandwidthUsage', 'amountOut')) projected = "{} GB".format(item.get('projectedPublicBandwidthUsage', 0)) table.add_row([id_bandwidth, name, region, servers, allocation, current, projected]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/account/bandwidth_pools_detail.py000066400000000000000000000062471437054676600261330ustar00rootroot00000000000000"""Get bandwidth pools.""" # :license: MIT, see LICENSE for more details. import click from SoftLayer import AccountManager from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer import utils @click.command(cls=SLCommand) @click.argument('identifier') @environment.pass_env def cli(env, identifier): """Get bandwidth pool details.""" manager = AccountManager(env.client) bandwidths = manager.getBandwidthDetail(identifier) table = formatting.KeyValueTable(['name', 'value']) table.align['name'] = 'r' table.align['value'] = 'l' table.add_row(['Id', bandwidths['id']]) table.add_row(['Name', bandwidths['name']]) table.add_row(['Create Date', utils.clean_time(bandwidths.get('createDate'), '%Y-%m-%d')]) current = "{} GB".format(utils.lookup(bandwidths, 'billingCyclePublicBandwidthUsage', 'amountOut')) if current is None: current = '-' table.add_row(['Current Usage', current]) projected = "{} GB".format(bandwidths.get('projectedPublicBandwidthUsage', 0)) if projected is None: projected = '-' table.add_row(['Projected Usage', projected]) inbound = "{} GB".format(bandwidths.get('inboundPublicBandwidthUsage', 0)) if inbound is None: inbound = '-' table.add_row(['Inbound Usage', inbound]) if bandwidths['hardware'] != []: table.add_row(['hardware', *(_bw_table(bandwidths['hardware']))]) else: table.add_row(['hardware', 'Not Found']) if bandwidths['virtualGuests'] != []: table.add_row(['virtualGuests', *(_virtual_table(bandwidths['virtualGuests']))]) else: table.add_row(['virtualGuests', 'Not Found']) if bandwidths['bareMetalInstances'] != []: table.add_row(['Netscaler', *(_bw_table(bandwidths['bareMetalInstances']))]) else: table.add_row(['Netscaler', 'Not Found']) env.fout(table) def _bw_table(bw_data): """Generates a bandwidth useage table""" table_data = formatting.Table(['Id', 'HostName', "IP Address", 'Amount', "Current Usage"]) for bw_point in bw_data: amount = "{} GB".format(utils.lookup(bw_point, 'bandwidthAllotmentDetail', 'allocation', 'amount')) current = "{} GB".format(bw_point.get('outboundBandwidthUsage', 0)) ip_address = bw_point.get('primaryIpAddress') if ip_address is None: ip_address = '-' table_data.add_row([bw_point['id'], bw_point['fullyQualifiedDomainName'], ip_address, amount, current]) return [table_data] def _virtual_table(bw_data): """Generates a virtual bandwidth usage table""" table_data = formatting.Table(['Id', 'HostName', "IP Address", 'Amount', "Current Usage"]) for bw_point in bw_data: amount = "{} GB".format(utils.lookup(bw_point, 'bandwidthAllotmentDetail', 'allocation', 'amount')) current = "{} GB".format(bw_point.get('outboundBandwidthUsage', 0)) ip_address = bw_point.get('primaryIpAddress') if ip_address is None: ip_address = '-' table_data.add_row([bw_point['id'], bw_point['fullyQualifiedDomainName'], ip_address, amount, current]) return [table_data] softlayer-python-6.1.4/SoftLayer/CLI/account/billing_items.py000066400000000000000000000037161437054676600242500ustar00rootroot00000000000000"""Lists all active billing items on this account. See https://cloud.ibm.com/billing/billing-items""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.account import AccountManager as AccountManager from SoftLayer import utils @click.command(cls=SLCommand) @environment.pass_env def cli(env): """Lists billing items with some other useful information. Similiar to https://cloud.ibm.com/billing/billing-items """ manager = AccountManager(env.client) items = manager.get_account_billing_items() table = item_table(items) env.fout(table) def item_table(items): """Formats a table for billing items""" table = formatting.Table([ "Id", "Create Date", "Cost", "Category Code", "Ordered By", "Description", "Notes" ], title="Billing Items") table.align['Description'] = 'l' table.align['Category Code'] = 'l' for item in items: description = item.get('description') fqdn = "{}.{}".format(item.get('hostName', ''), item.get('domainName', '')) if fqdn != ".": description = fqdn user = utils.lookup(item, 'orderItem', 'order', 'userRecord') ordered_by = "IBM" create_date = utils.clean_time(item.get('createDate'), in_format='%Y-%m-%d', out_format='%Y-%m-%d') if user: # ordered_by = "{} ({})".format(user.get('displayName'), utils.lookup(user, 'userStatus', 'name')) ordered_by = user.get('displayName') table.add_row([ item.get('id'), create_date, item.get('nextInvoiceTotalRecurringAmount'), item.get('categoryCode'), ordered_by, utils.trim_to(description, 50), utils.trim_to(item.get('notes', 'None'), 40), ]) return table softlayer-python-6.1.4/SoftLayer/CLI/account/cancel_item.py000066400000000000000000000010641437054676600236640ustar00rootroot00000000000000"""Cancels a billing item.""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.managers.account import AccountManager as AccountManager @click.command(cls=SLCommand) @click.argument('identifier') @environment.pass_env def cli(env, identifier): """Cancels a billing item.""" manager = AccountManager(env.client) item = manager.cancel_item(identifier) if item: env.fout("Item: {} was cancelled.".format(identifier)) softlayer-python-6.1.4/SoftLayer/CLI/account/event_detail.py000066400000000000000000000046041437054676600240670ustar00rootroot00000000000000"""Details of a specific event, and ability to acknowledge event.""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.account import AccountManager as AccountManager from SoftLayer import utils @click.command(cls=SLCommand) @click.argument('identifier') @click.option('--ack', is_flag=True, default=False, help="Acknowledge Event. Doing so will turn off the popup in the control portal") @environment.pass_env def cli(env, identifier, ack): """Details of a specific event, and ability to acknowledge event.""" # Print a list of all on going maintenance manager = AccountManager(env.client) event = manager.get_event(identifier) if ack: manager.ack_event(identifier) env.fout(basic_event_table(event)) env.fout(impacted_table(event)) env.fout(update_table(event)) def basic_event_table(event): """Formats a basic event table""" table = formatting.Table(["Id", "Status", "Type", "Start", "End"], title=utils.clean_splitlines(event.get('subject'))) table.add_row([ event.get('id'), utils.lookup(event, 'statusCode', 'name'), utils.lookup(event, 'notificationOccurrenceEventType', 'keyName'), utils.clean_time(event.get('startDate')), utils.clean_time(event.get('endDate')) ]) return table def impacted_table(event): """Formats a basic impacted resources table""" table = formatting.Table([ "Type", "Id", "Hostname", "PrivateIp", "Label" ]) for item in event.get('impactedResources', []): table.add_row([ item.get('resourceType'), item.get('resourceTableId'), item.get('hostname'), item.get('privateIp'), item.get('filterLabel') ]) return table def update_table(event): """Formats a basic event update table""" update_number = 0 for update in event.get('updates', []): update_number = update_number + 1 header = "======= Update #%s on %s =======" % (update_number, utils.clean_time(update.get('startDate'))) click.secho(header, fg='green') text = update.get('contents') # deals with all the \r\n from the API click.secho(utils.clean_splitlines(text)) softlayer-python-6.1.4/SoftLayer/CLI/account/events.py000066400000000000000000000120301437054676600227200ustar00rootroot00000000000000"""Summary and acknowledgement of upcoming and ongoing maintenance events""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.account import AccountManager as AccountManager from SoftLayer import utils @click.command(cls=SLCommand) @click.option('--announcement', is_flag=True, default=False, help="Show only announcement events.") @click.option('--ack-all', is_flag=True, default=False, help="Acknowledge every upcoming event. Doing so will turn off the popup in the control portal.") @click.option('--date-min', help="Earliest date to retrieve events for [MM/DD/YYYY]. Default: 2 days ago.") @click.option('--planned', is_flag=True, default=False, help="Show only planned events.") @click.option('--unplanned', is_flag=True, default=False, help="Show only unplanned events.") @environment.pass_env def cli(env, ack_all, planned, unplanned, announcement, date_min): """Summary and acknowledgement of upcoming and ongoing maintenance events""" if date_min: utils.verify_date(date_min) manager = AccountManager(env.client) planned_events = manager.get_upcoming_events("PLANNED", date_min) unplanned_events = manager.get_upcoming_events("UNPLANNED_INCIDENT", date_min) announcement_events = manager.get_upcoming_events("ANNOUNCEMENT", date_min) add_ack_flag(planned_events, manager, ack_all) add_ack_flag(unplanned_events, manager, ack_all) add_ack_flag(announcement_events, manager, ack_all) if planned: env.fout(planned_event_table(planned_events)) if unplanned: env.fout(unplanned_event_table(unplanned_events)) if announcement: env.fout(announcement_event_table(announcement_events)) if not planned and not unplanned and not announcement: env.fout(planned_event_table(planned_events)) env.fout(unplanned_event_table(unplanned_events)) env.fout(announcement_event_table(announcement_events)) def add_ack_flag(events, manager, ack_all): """Add acknowledgedFlag to the event""" if ack_all: for event in events: result = manager.ack_event(event['id']) event['acknowledgedFlag'] = result def planned_event_table(events): """Formats a table for events""" planned_table = formatting.Table(['Event Data', 'Id', 'Event ID', 'Subject', 'Status', 'Items', 'Start Date', 'End Date', 'Acknowledged', 'Updates'], title="Planned Events") planned_table.align['Subject'] = 'l' planned_table.align['Impacted Resources'] = 'l' for event in events: planned_table.add_row([ utils.clean_time(event.get('startDate')), event.get('id'), event.get('systemTicketId'), # Some subjects can have \r\n for some reason. utils.clean_splitlines(event.get('subject')), utils.lookup(event, 'statusCode', 'name'), event.get('impactedResourceCount'), utils.clean_time(event.get('startDate')), utils.clean_time(event.get('endDate')), event.get('acknowledgedFlag'), event.get('updateCount'), ]) return planned_table def unplanned_event_table(events): """Formats a table for events""" unplanned_table = formatting.Table(['Id', 'Event ID', 'Subject', 'Status', 'Items', 'Start Date', 'Last Updated', 'Acknowledged', 'Updates'], title="Unplanned Events") unplanned_table.align['Subject'] = 'l' unplanned_table.align['Impacted Resources'] = 'l' for event in events: unplanned_table.add_row([ event.get('id'), event.get('systemTicketId'), # Some subjects can have \r\n for some reason. utils.clean_splitlines(event.get('subject')), utils.lookup(event, 'statusCode', 'name'), event.get('impactedResourceCount'), utils.clean_time(event.get('startDate')), utils.clean_time(event.get('modifyDate')), event.get('acknowledgedFlag'), event.get('updateCount'), ]) return unplanned_table def announcement_event_table(events): """Formats a table for events""" announcement_table = formatting.Table( ['Id', 'Event ID', 'Subject', 'Status', 'Items', 'Acknowledged', 'Updates'], title="Announcement Events") announcement_table.align['Subject'] = 'l' announcement_table.align['Impacted Resources'] = 'l' for event in events: announcement_table.add_row([ event.get('id'), event.get('systemTicketId'), # Some subjects can have \r\n for some reason. utils.clean_splitlines(event.get('subject')), utils.lookup(event, 'statusCode', 'name'), event.get('impactedResourceCount'), event.get('acknowledgedFlag'), event.get('updateCount') ]) return announcement_table softlayer-python-6.1.4/SoftLayer/CLI/account/invoice_detail.py000066400000000000000000000053141437054676600244010ustar00rootroot00000000000000"""Invoice details""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.account import AccountManager as AccountManager from SoftLayer import utils @click.command(cls=SLCommand) @click.argument('identifier') @click.option('--details', is_flag=True, default=False, show_default=True, help="Shows a very detailed list of charges") @environment.pass_env def cli(env, identifier, details): """Invoice details""" manager = AccountManager(env.client) top_items = manager.get_billing_items(identifier) table = get_invoice_table(identifier, top_items, details) env.fout(table) def nice_string(ugly_string, limit=100): """Format and trims strings""" return (ugly_string[:limit] + '..') if len(ugly_string) > limit else ugly_string def get_invoice_table(identifier, top_items, details): """Formats a table for invoice top level items. :param int identifier: Invoice identifier. :param list top_items: invoiceTopLevelItems. :param bool details: To add very detailed list of charges. """ title = "Invoice %s" % identifier table = formatting.Table(["Item Id", "Category", "Description", "Single", "Monthly", "Create Date", "Location"], title=title) table.align['category'] = 'l' table.align['description'] = 'l' for item in top_items: fqdn = "%s.%s" % (item.get('hostName', ''), item.get('domainName', '')) # category id=2046, ram_usage doesn't have a name... category = utils.lookup(item, 'category', 'name') or item.get('categoryCode') description = nice_string(item.get('description')) if fqdn != '.': description = "%s (%s)" % (item.get('description'), fqdn) table.add_row([ item.get('id'), category, nice_string(description), "$%.2f" % float(item.get('oneTimeAfterTaxAmount')), "$%.2f" % float(item.get('recurringAfterTaxAmount')), utils.clean_time(item.get('createDate'), out_format="%Y-%m-%d"), utils.lookup(item, 'location', 'name') ]) if details: for child in item.get('children', []): table.add_row([ '>>>', utils.lookup(child, 'category', 'name'), nice_string(child.get('description')), "$%.2f" % float(child.get('oneTimeAfterTaxAmount')), "$%.2f" % float(child.get('recurringAfterTaxAmount')), '---', '---' ]) return table softlayer-python-6.1.4/SoftLayer/CLI/account/invoices.py000066400000000000000000000033251437054676600232420ustar00rootroot00000000000000"""Invoice listing""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.account import AccountManager as AccountManager from SoftLayer import utils @click.command(cls=SLCommand) @click.option('--all', 'get_all', is_flag=True, default=False, show_default=True, help="Return ALL invoices. There may be a lot of these.") @click.option('--closed', is_flag=True, default=False, show_default=True, help="Include invoices with a CLOSED status.") @click.option('--limit', default=50, show_default=True, help="How many invoices to get back.") @environment.pass_env def cli(env, limit, closed=False, get_all=False): """List invoices""" manager = AccountManager(env.client) invoices = manager.get_invoices(limit, closed, get_all) table = formatting.Table([ "Id", "Created", "Type", "Status", "Starting Balance", "Ending Balance", "Invoice Amount", "Items" ]) table.align['Starting Balance'] = 'l' table.align['Ending Balance'] = 'l' table.align['Invoice Amount'] = 'l' table.align['Items'] = 'l' if isinstance(invoices, dict): invoices = [invoices] for invoice in invoices: table.add_row([ invoice.get('id'), utils.clean_time(invoice.get('createDate'), out_format="%Y-%m-%d"), invoice.get('typeCode'), invoice.get('statusCode'), invoice.get('startingBalance'), invoice.get('endingBalance'), invoice.get('invoiceTotalAmount'), invoice.get('itemCount') ]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/account/item_detail.py000066400000000000000000000043301437054676600237000ustar00rootroot00000000000000"""Gets some details about a specific billing item.""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.account import AccountManager as AccountManager from SoftLayer import utils @click.command(cls=SLCommand) @click.argument('identifier') @environment.pass_env def cli(env, identifier): """Gets detailed information about a billing item.""" manager = AccountManager(env.client) item = manager.get_item_detail(identifier) env.fout(item_table(item)) def item_table(item): """Formats a table for billing items""" date_format = '%Y-%m-%d' table = formatting.Table(["Key", "Value"], title="{}".format(item.get('description', 'Billing Item'))) table.add_row(['createDate', utils.clean_time(item.get('createDate'), date_format, date_format)]) table.add_row(['cycleStartDate', utils.clean_time(item.get('cycleStartDate'), date_format, date_format)]) table.add_row(['cancellationDate', utils.clean_time(item.get('cancellationDate'), date_format, date_format)]) table.add_row(['description', item.get('description')]) table.align = 'l' fqdn = "{}.{}".format(item.get('hostName', ''), item.get('domainName', '')) if fqdn != ".": table.add_row(['FQDN', fqdn]) if item.get('hourlyFlag', False): table.add_row(['hourlyRecurringFee', item.get('hourlyRecurringFee')]) table.add_row(['hoursUsed', item.get('hoursUsed')]) table.add_row(['currentHourlyCharge', item.get('currentHourlyCharge')]) else: table.add_row(['recurringFee', item.get('recurringFee')]) ordered_by = "IBM" user = utils.lookup(item, 'orderItem', 'order', 'userRecord') if user: ordered_by = "{} ({})".format(user.get('displayName'), utils.lookup(user, 'userStatus', 'name')) table.add_row(['Ordered By', ordered_by]) table.add_row(['Notes', item.get('notes')]) table.add_row(['Location', utils.lookup(item, 'location', 'name')]) if item.get('children'): for child in item.get('children'): table.add_row([child.get('categoryCode'), child.get('description')]) return table softlayer-python-6.1.4/SoftLayer/CLI/account/licenses.py000066400000000000000000000035721437054676600232340ustar00rootroot00000000000000"""Show all licenses.""" # :license: MIT, see LICENSE for more details. import click from SoftLayer import utils from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers import account @click.command(cls=SLCommand) @environment.pass_env def cli(env): """Show all licenses.""" manager = account.AccountManager(env.client) control_panel = manager.get_active_virtual_licenses() vmwares = manager.get_active_account_licenses() table_panel = formatting.KeyValueTable(['id', 'ip_address', 'manufacturer', 'software', 'key', 'subnet', 'subnet notes'], title="Control Panel Licenses") table_vmware = formatting.KeyValueTable(['name', 'license_key', 'cpus', 'description', 'manufacturer', 'requiredUser'], title="VMware Licenses") for panel in control_panel: table_panel.add_row([panel.get('id'), panel.get('ipAddress'), utils.lookup(panel, 'softwareDescription', 'manufacturer'), utils.trim_to(utils.lookup(panel, 'softwareDescription', 'longDescription'), 40), panel.get('key'), utils.lookup(panel, 'subnet', 'broadcastAddress'), utils.lookup(panel, 'subnet', 'note')]) env.fout(table_panel) for vmware in vmwares: table_vmware.add_row([utils.lookup(vmware, 'softwareDescription', 'name'), vmware.get('key'), vmware.get('capacity'), utils.lookup(vmware, 'billingItem', 'description'), utils.lookup(vmware, 'softwareDescription', 'manufacturer'), utils.lookup(vmware, 'softwareDescription', 'requiredUser')]) env.fout(table_vmware) softlayer-python-6.1.4/SoftLayer/CLI/account/orders.py000066400000000000000000000025551437054676600227250ustar00rootroot00000000000000"""Lists account orders.""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.account import AccountManager as AccountManager from SoftLayer import utils @click.command(cls=SLCommand) @click.option('--limit', '-l', help='How many results to get in one api call', default=50, show_default=True) @environment.pass_env def cli(env, limit): """Lists account orders. Use `slcli order lookup ` to find more details about a specific order.""" manager = AccountManager(env.client) orders = manager.get_account_all_billing_orders(limit) order_table = formatting.Table(['Id', 'State', 'User', 'Date', 'Amount', 'Item'], title="orders") order_table.align = 'l' for order in orders: items = [] for item in order['items']: items.append(item['description']) create_date = utils.clean_time(order['createDate'], in_format='%Y-%m-%d', out_format='%Y-%m-%d') order_table.add_row([order['id'], order['status'], order['userRecord']['username'], create_date, order['orderTotalAmount'], utils.trim_to(' '.join(map(str, items)), 50)]) env.fout(order_table) softlayer-python-6.1.4/SoftLayer/CLI/account/summary.py000066400000000000000000000034501437054676600231170ustar00rootroot00000000000000"""Account Summary page""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.account import AccountManager as AccountManager from SoftLayer import utils @click.command(cls=SLCommand) @environment.pass_env def cli(env): """Prints some various bits of information about an account""" manager = AccountManager(env.client) summary = manager.get_summary() env.fout(get_snapshot_table(summary)) def get_snapshot_table(account): """Generates a table for printing account summary data""" table = formatting.KeyValueTable(["Name", "Value"], title="Account Snapshot") table.align['Name'] = 'r' table.align['Value'] = 'l' table.add_row(['Company Name', account.get('companyName', '-')]) table.add_row(['Balance', utils.lookup(account, 'pendingInvoice', 'startingBalance')]) table.add_row(['Upcoming Invoice', utils.lookup(account, 'pendingInvoice', 'invoiceTotalAmount')]) table.add_row(['Image Templates', account.get('blockDeviceTemplateGroupCount', '-')]) table.add_row(['Dedicated Hosts', account.get('dedicatedHostCount', '-')]) table.add_row(['Hardware', account.get('hardwareCount', '-')]) table.add_row(['Virtual Guests', account.get('virtualGuestCount', '-')]) table.add_row(['Domains', account.get('domainCount', '-')]) table.add_row(['Network Storage Volumes', account.get('networkStorageCount', '-')]) table.add_row(['Open Tickets', account.get('openTicketCount', '-')]) table.add_row(['Network Vlans', account.get('networkVlanCount', '-')]) table.add_row(['Subnets', account.get('subnetCount', '-')]) table.add_row(['Users', account.get('userCount', '-')]) return table softlayer-python-6.1.4/SoftLayer/CLI/autoscale/000077500000000000000000000000001437054676600213725ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/CLI/autoscale/__init__.py000066400000000000000000000000201437054676600234730ustar00rootroot00000000000000"""Autoscale""" softlayer-python-6.1.4/SoftLayer/CLI/autoscale/delete.py000066400000000000000000000013761437054676600232150ustar00rootroot00000000000000"""Delete autoscale.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.managers.autoscale import AutoScaleManager @click.command(cls=SLCommand) @click.argument('identifier') @environment.pass_env def cli(env, identifier): """Delete this group and destroy all members of it. Example: slcli autoscale delete autoscaleId """ autoscale = AutoScaleManager(env.client) try: autoscale.delete(identifier) click.secho("%s deleted successfully" % identifier, fg='green') except SoftLayer.SoftLayerAPIError as ex: click.secho("Failed to delete %s\n%s" % (identifier, ex), fg='red') softlayer-python-6.1.4/SoftLayer/CLI/autoscale/detail.py000066400000000000000000000076101437054676600232120ustar00rootroot00000000000000"""Get details of an Autoscale groups.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.autoscale import AutoScaleManager from SoftLayer import utils @click.command(cls=SLCommand) @click.argument('identifier') @environment.pass_env def cli(env, identifier): """Get details of an Autoscale group.""" autoscale = AutoScaleManager(env.client) group = autoscale.details(identifier) # Group Config Table table = formatting.KeyValueTable(["Group", "Value"]) table.align['Group'] = 'l' table.align['Value'] = 'l' table.add_row(['Id', group.get('id')]) # Ideally we would use regionalGroup->preferredDatacenter, but that generates an error. table.add_row(['Datacenter', group['regionalGroup']['locations'][0]['longName']]) table.add_row(['Termination', utils.lookup(group, 'terminationPolicy', 'name')]) table.add_row(['Minimum Members', group.get('minimumMemberCount')]) table.add_row(['Maximum Members', group.get('maximumMemberCount')]) table.add_row(['Current Members', group.get('virtualGuestMemberCount')]) table.add_row(['Cooldown', "{} seconds".format(group.get('cooldown'))]) table.add_row(['Last Action', utils.clean_time(group.get('lastActionDate'))]) for network in group.get('networkVlans', []): network_type = utils.lookup(network, 'networkVlan', 'networkSpace') router = utils.lookup(network, 'networkVlan', 'primaryRouter', 'hostname') vlan_number = utils.lookup(network, 'networkVlan', 'vlanNumber') vlan_name = "{}.{}".format(router, vlan_number) table.add_row([network_type, vlan_name]) env.fout(table) # Template Config Table config_table = formatting.KeyValueTable(["Template", "Value"]) config_table.align['Template'] = 'l' config_table.align['Value'] = 'l' template = group.get('virtualGuestMemberTemplate') config_table.add_row(['Hostname', template.get('hostname')]) config_table.add_row(['Domain', template.get('domain')]) config_table.add_row(['Core', template.get('startCpus')]) config_table.add_row(['Ram', template.get('maxMemory')]) network = template.get('networkComponents') config_table.add_row(['Network', network[0]['maxSpeed'] if network else 'Default']) ssh_keys = template.get('sshKeys', []) ssh_manager = SoftLayer.SshKeyManager(env.client) for key in ssh_keys: # Label isn't included when retrieved from the AutoScale group... ssh_key = ssh_manager.get_key(key.get('id')) config_table.add_row(['SSH Key {}'.format(ssh_key.get('id')), ssh_key.get('label')]) disks = template.get('blockDevices', []) disk_type = "Local" if template.get('localDiskFlag') else "SAN" for disk in disks: disk_image = disk.get('diskImage') config_table.add_row(['{} Disk {}'.format(disk_type, disk.get('device')), disk_image.get('capacity')]) config_table.add_row(['OS', template.get('operatingSystemReferenceCode')]) config_table.add_row(['Post Install', template.get('postInstallScriptUri') or 'None']) env.fout(config_table) # Policy Config Table policy_table = formatting.KeyValueTable(["Policy", "Cooldown"]) policies = group.get('policies', []) for policy in policies: policy_table.add_row([policy.get('name'), policy.get('cooldown') or group.get('cooldown')]) env.fout(policy_table) # Active Guests member_table = formatting.Table(['Id', 'Hostname', 'Created'], title="Active Guests") guests = group.get('virtualGuestMembers', []) for guest in guests: real_guest = guest.get('virtualGuest') member_table.add_row([ real_guest.get('id'), real_guest.get('hostname'), utils.clean_time(real_guest.get('provisionDate')) ]) env.fout(member_table) softlayer-python-6.1.4/SoftLayer/CLI/autoscale/list.py000066400000000000000000000016671437054676600227310ustar00rootroot00000000000000"""List Autoscale groups.""" # :license: MIT, see LICENSE for more details. import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.managers.autoscale import AutoScaleManager from SoftLayer import utils @click.command(cls=SLCommand) @environment.pass_env def cli(env): """List all Autoscale Groups on your account.""" autoscale = AutoScaleManager(env.client) groups = autoscale.list() table = formatting.Table(["Id", "Name", "Status", "Min/Max", "Running"]) table.align['Name'] = 'l' for group in groups: status = utils.lookup(group, 'status', 'name') min_max = "{}/{}".format(group.get('minimumMemberCount'), group.get('maximumMemberCount')) table.add_row([ group.get('id'), group.get('name'), status, min_max, group.get('virtualGuestMemberCount') ]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/000077500000000000000000000000001437054676600205045ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/CLI/block/__init__.py000066400000000000000000000000251437054676600226120ustar00rootroot00000000000000"""Block Storage.""" softlayer-python-6.1.4/SoftLayer/CLI/block/access/000077500000000000000000000000001437054676600217455ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/CLI/block/access/__init__.py000066400000000000000000000000441437054676600240540ustar00rootroot00000000000000"""Block Storage Access Control.""" softlayer-python-6.1.4/SoftLayer/CLI/block/access/authorize.py000066400000000000000000000035271437054676600243400ustar00rootroot00000000000000"""Authorizes hosts on a specific block volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions MULTIPLE = '(Multiple allowed)' @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option('--hardware-id', '-d', multiple=True, help='The ID of one hardware server to authorize. ' + MULTIPLE) @click.option('--ip-address-id', '-i', multiple=True, help='The ID of one SoftLayer_Network_Subnet_IpAddress to authorize. ' + MULTIPLE) @click.option('--ip-address', multiple=True, help='An IP address to authorize. ' + MULTIPLE) @click.option('--virtual-id', '-v', multiple=True, help='The ID of one virtual server to authorize. ' + MULTIPLE) @environment.pass_env def cli(env, volume_id, hardware_id, virtual_id, ip_address_id, ip_address): """Authorize hosts to access a given volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) ip_address_id_list = list(ip_address_id) # Convert actual IP Addresses to their SoftLayer ids if ip_address is not None: network_manager = SoftLayer.NetworkManager(env.client) for ip_address_value in ip_address: ip_address_object = network_manager.ip_lookup(ip_address_value) if ip_address_object == "": click.echo("IP Address not found on your account. Please confirm IP and try again.") raise exceptions.ArgumentError('Incorrect IP Address') ip_address_id_list.append(ip_address_object['id']) block_manager.authorize_host_to_volume(volume_id, hardware_id, virtual_id, ip_address_id_list) # If no exception was raised, the command succeeded click.echo('The specified hosts were authorized to access %s' % volume_id) softlayer-python-6.1.4/SoftLayer/CLI/block/access/list.py000066400000000000000000000034331437054676600232750ustar00rootroot00000000000000"""List hosts with access to block volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import columns as column_helper from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.CLI import helpers from SoftLayer.CLI import storage_utils @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option('--columns', callback=column_helper.get_formatter(storage_utils.COLUMNS), help='Columns to display. Options are: {0}.'.format( ', '.join(column.name for column in storage_utils.COLUMNS)), default=','.join(storage_utils.DEFAULT_COLUMNS)) @click.option('--sortby', help='Column to sort by. Options are: {0}.'.format( ', '.join(column.name for column in storage_utils.COLUMNS)), default='name') @environment.pass_env def cli(env, columns, sortby, volume_id): """List hosts that are authorized to access the volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) resolved_id = helpers.resolve_id(block_manager.resolve_ids, volume_id, 'Volume Id') access_list = block_manager.get_block_volume_access_list( volume_id=resolved_id) table = formatting.Table(columns.columns) table.sortby = sortby for key, type_name in [('allowedVirtualGuests', 'VIRTUAL'), ('allowedHardware', 'HARDWARE'), ('allowedSubnets', 'SUBNET'), ('allowedIpAddresses', 'IP')]: for obj in access_list.get(key, []): obj['type'] = type_name table.add_row([value or formatting.blank() for value in columns.row(obj)]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/access/password.py000066400000000000000000000015671437054676600241720ustar00rootroot00000000000000"""Modifies a password for a volume's access""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('access_id') @click.option('--password', '-p', multiple=False, help='Password you want to set, this command will fail if the password is not strong.') @environment.pass_env def cli(env, access_id, password): """Changes a password for a volume's access. access id is the allowed_host_id from slcli block access-list """ block_manager = SoftLayer.BlockStorageManager(env.client) result = block_manager.set_credential_password(access_id=access_id, password=password) if result: click.echo('Password updated for %s' % access_id) else: click.echo('FAILED updating password for %s' % access_id) softlayer-python-6.1.4/SoftLayer/CLI/block/access/revoke.py000066400000000000000000000033561437054676600236210ustar00rootroot00000000000000"""Revokes hosts' access on a specific block volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option('--hardware-id', '-d', multiple=True, help='The ID of one SoftLayer_Hardware to revoke authorization.') @click.option('--ip-address-id', '-i', multiple=True, help='The ID of one SoftLayer_Network_Subnet_IpAddress to revoke authorization.') @click.option('--ip-address', multiple=True, help='An IP address to revoke authorization.') @click.option('--virtual-id', '-v', multiple=True, help='The ID of one SoftLayer_Virtual_Guest to revoke authorization.') @environment.pass_env def cli(env, volume_id, hardware_id, virtual_id, ip_address_id, ip_address): """Revoke authorization for hosts that are accessing a specific volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) ip_address_id_list = list(ip_address_id) # Convert actual IP Addresses to their SoftLayer ids if ip_address is not None: network_manager = SoftLayer.NetworkManager(env.client) for ip_address_value in ip_address: ip_address_object = network_manager.ip_lookup(ip_address_value) ip_address_id_list.append(ip_address_object['id']) block_manager.deauthorize_host_to_volume(volume_id, hardware_id, virtual_id, ip_address_id_list) # If no exception was raised, the command succeeded click.echo('Access to %s was revoked for the specified hosts' % volume_id) softlayer-python-6.1.4/SoftLayer/CLI/block/cancel.py000066400000000000000000000026031437054676600223040ustar00rootroot00000000000000"""Cancel an existing iSCSI account.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume-id') @click.option('--reason', help="An optional reason for cancellation") @click.option('--immediate', is_flag=True, help="Cancels the block storage volume immediately instead " "of on the billing anniversary") @environment.pass_env def cli(env, volume_id, reason, immediate): """Cancel an existing block storage volume.""" block_storage_manager = SoftLayer.BlockStorageManager(env.client) if not (env.skip_confirmations or formatting.no_going_back(volume_id)): raise exceptions.CLIAbort('Aborted') cancelled = block_storage_manager.cancel_block_volume(volume_id, reason, immediate) if cancelled: if immediate: click.echo('Block volume with id %s has been marked' ' for immediate cancellation' % volume_id) else: click.echo('Block volume with id %s has been marked' ' for cancellation' % volume_id) else: click.echo('Unable to cancel block volume %s' % volume_id) softlayer-python-6.1.4/SoftLayer/CLI/block/convert.py000066400000000000000000000010171437054676600225350ustar00rootroot00000000000000"""Convert a dependent duplicate volume to an independent volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @environment.pass_env def cli(env, volume_id): """Convert a dependent duplicate volume to an independent volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) resp = block_manager.convert_dep_dupe(volume_id) click.echo(resp) softlayer-python-6.1.4/SoftLayer/CLI/block/count.py000066400000000000000000000031011437054676600222010ustar00rootroot00000000000000"""List number of block storage volumes per datacenter.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting DEFAULT_COLUMNS = [ 'Datacenter', 'Count' ] @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.option('--datacenter', '-d', help='Datacenter shortname') @click.option('--sortby', help='Column to sort by', default='Datacenter') @environment.pass_env def cli(env, sortby, datacenter): """List number of block storage volumes per datacenter.""" block_manager = SoftLayer.BlockStorageManager(env.client) mask = "mask[serviceResource[datacenter[name]],"\ "replicationPartners[serviceResource[datacenter[name]]]]" block_volumes = block_manager.list_block_volumes(datacenter=datacenter, mask=mask) # cycle through all block volumes and count datacenter occurences. datacenters = {} for volume in block_volumes: service_resource = volume['serviceResource'] if 'datacenter' in service_resource: datacenter_name = service_resource['datacenter']['name'] if datacenter_name not in datacenters.keys(): # pylint: disable=consider-iterating-dictionary datacenters[datacenter_name] = 1 else: datacenters[datacenter_name] += 1 table = formatting.KeyValueTable(DEFAULT_COLUMNS) table.sortby = sortby for key, value in datacenters.items(): table.add_row([key, value]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/detail.py000066400000000000000000000113421437054676600223210ustar00rootroot00000000000000"""Display details for a specified volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.CLI import helpers from SoftLayer import utils @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @environment.pass_env def cli(env, volume_id): """Display details for a specified volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) block_volume_id = helpers.resolve_id(block_manager.resolve_ids, volume_id, 'Block Volume') block_volume = block_manager.get_block_volume_details(block_volume_id) block_volume = utils.NestedDict(block_volume) table = formatting.KeyValueTable(['Name', 'Value']) table.align['Name'] = 'r' table.align['Value'] = 'l' storage_type = block_volume['storageType']['keyName'].split('_').pop(0) table.add_row(['ID', block_volume['id']]) table.add_row(['Username', block_volume['username']]) table.add_row(['Type', storage_type]) table.add_row(['Capacity (GB)', "%iGB" % block_volume['capacityGb']]) table.add_row(['LUN Id', "%s" % block_volume['lunId']]) if block_volume.get('provisionedIops'): table.add_row(['IOPs', float(block_volume['provisionedIops'])]) if block_volume.get('storageTierLevel'): table.add_row([ 'Endurance Tier', block_volume['storageTierLevel'], ]) table.add_row([ 'Data Center', block_volume['serviceResource']['datacenter']['name'], ]) table.add_row([ 'Target IP', block_volume['serviceResourceBackendIpAddress'], ]) if block_volume['snapshotCapacityGb']: table.add_row([ 'Snapshot Capacity (GB)', block_volume['snapshotCapacityGb'], ]) if 'snapshotSizeBytes' in block_volume['parentVolume']: table.add_row([ 'Snapshot Used (Bytes)', block_volume['parentVolume']['snapshotSizeBytes'], ]) table.add_row(['# of Active Transactions', "%i" % block_volume['activeTransactionCount']]) if block_volume['activeTransactions']: for trans in block_volume['activeTransactions']: if 'transactionStatus' in trans and 'friendlyName' in trans['transactionStatus']: table.add_row(['Ongoing Transaction', trans['transactionStatus']['friendlyName']]) table.add_row(['Replicant Count', "%u" % block_volume.get('replicationPartnerCount', 0)]) if block_volume['replicationPartnerCount'] > 0: # This if/else temporarily handles a bug in which the SL API # returns a string or object for 'replicationStatus'; it seems that # the type is string for File volumes and object for Block volumes if 'message' in block_volume['replicationStatus']: table.add_row(['Replication Status', "%s" % block_volume['replicationStatus']['message']]) else: table.add_row(['Replication Status', "%s" % block_volume['replicationStatus']]) for replicant in block_volume['replicationPartners']: replicant_table = formatting.Table(['Name', 'Value']) replicant_table.add_row(['Replicant Id', replicant['id']]) replicant_table.add_row([ 'Volume Name', utils.lookup(replicant, 'username')]) replicant_table.add_row([ 'Target IP', utils.lookup(replicant, 'serviceResourceBackendIpAddress')]) replicant_table.add_row([ 'Data Center', utils.lookup(replicant, 'serviceResource', 'datacenter', 'name')]) replicant_table.add_row([ 'Schedule', utils.lookup(replicant, 'replicationSchedule', 'type', 'keyname')]) table.add_row(['Replicant Volumes', replicant_table]) if block_volume.get('originalVolumeSize'): original_volume_info = formatting.Table(['Property', 'Value']) original_volume_info.add_row(['Original Volume Size', block_volume['originalVolumeSize']]) if block_volume.get('originalVolumeName'): original_volume_info.add_row(['Original Volume Name', block_volume['originalVolumeName']]) if block_volume.get('originalSnapshotName'): original_volume_info.add_row(['Original Snapshot Name', block_volume['originalSnapshotName']]) table.add_row(['Original Volume Properties', original_volume_info]) notes = '{}'.format(block_volume.get('notes', '')) table.add_row(['Notes', notes]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/duplicate.py000066400000000000000000000107301437054676600230310ustar00rootroot00000000000000"""Order a duplicate block storage volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()} @click.command(cls=SoftLayer.CLI.command.SLCommand, context_settings=CONTEXT_SETTINGS) @click.argument('origin-volume-id') @click.option('--origin-snapshot-id', '-o', type=int, help="ID of an origin volume snapshot to use for duplcation.") @click.option('--duplicate-size', '-c', type=int, help='Size of duplicate block volume in GB. ' '***If no size is specified, the size of ' 'the origin volume will be used.***\n' 'Potential Sizes: [20, 40, 80, 100, 250, ' '500, 1000, 2000, 4000, 8000, 12000] ' 'Minimum: [the size of the origin volume]') @click.option('--duplicate-iops', '-i', type=int, help='Performance Storage IOPS, between 100 and 6000 in ' 'multiples of 100 [only used for performance volumes] ' '***If no IOPS value is specified, the IOPS value of the ' 'origin volume will be used.***\n' 'Requirements: [If IOPS/GB for the origin volume is less ' 'than 0.3, IOPS/GB for the duplicate must also be less ' 'than 0.3. If IOPS/GB for the origin volume is greater ' 'than or equal to 0.3, IOPS/GB for the duplicate must ' 'also be greater than or equal to 0.3.]') @click.option('--duplicate-tier', '-t', help='Endurance Storage Tier (IOPS per GB) [only used for ' 'endurance volumes] ***If no tier is specified, the tier ' 'of the origin volume will be used.***\n' 'Requirements: [If IOPS/GB for the origin volume is 0.25, ' 'IOPS/GB for the duplicate must also be 0.25. If IOPS/GB ' 'for the origin volume is greater than 0.25, IOPS/GB ' 'for the duplicate must also be greater than 0.25.]', type=click.Choice(['0.25', '2', '4', '10'])) @click.option('--duplicate-snapshot-size', '-s', type=int, help='The size of snapshot space to order for the duplicate. ' '***If no snapshot space size is specified, the snapshot ' 'space size of the origin block volume will be used.***\n' 'Input "0" for this parameter to order a duplicate volume ' 'with no snapshot space.') @click.option('--billing', type=click.Choice(['hourly', 'monthly']), default='monthly', help="Optional parameter for Billing rate (default to monthly)") @click.option('--dependent-duplicate', type=click.BOOL, default=False, show_default=True, help='Whether or not this duplicate will be a dependent duplicate ' 'of the origin volume.') @environment.pass_env def cli(env, origin_volume_id, origin_snapshot_id, duplicate_size, duplicate_iops, duplicate_tier, duplicate_snapshot_size, billing, dependent_duplicate): """Order a duplicate block storage volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) hourly_billing_flag = False if billing.lower() == "hourly": hourly_billing_flag = True if duplicate_tier is not None: duplicate_tier = float(duplicate_tier) try: order = block_manager.order_duplicate_volume( origin_volume_id, origin_snapshot_id=origin_snapshot_id, duplicate_size=duplicate_size, duplicate_iops=duplicate_iops, duplicate_tier_level=duplicate_tier, duplicate_snapshot_size=duplicate_snapshot_size, hourly_billing_flag=hourly_billing_flag, dependent_duplicate=dependent_duplicate ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) if 'placedOrder' in order.keys(): click.echo("Order #{0} placed successfully!".format( order['placedOrder']['id'])) for item in order['placedOrder']['items']: click.echo(" > %s" % item['description']) else: click.echo("Order could not be placed! Please verify your options " + "and try again.") softlayer-python-6.1.4/SoftLayer/CLI/block/duplicate_convert_status.py000066400000000000000000000017651437054676600262040ustar00rootroot00000000000000"""Get status for split or move completed percentage of a given block duplicate volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, epilog="""Get status for split or move completed percentage of a given block duplicate volume.""") @click.argument('volume-id') @environment.pass_env def cli(env, volume_id): """Get status for split or move completed percentage of a given block duplicate volume.""" table = formatting.Table(['Username', 'Active Conversion Start Timestamp', 'Completed Percentage']) block_manager = SoftLayer.BlockStorageManager(env.client) value = block_manager.convert_dupe_status(volume_id) table.add_row( [ value['volumeUsername'], value['activeConversionStartTime'], value['deDuplicateConversionPercentage'] ] ) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/limit.py000066400000000000000000000020531437054676600221740ustar00rootroot00000000000000"""List number of block storage volumes limit per datacenter.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting DEFAULT_COLUMNS = [ 'Datacenter', 'MaximumAvailableCount', 'ProvisionedCount' ] @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.option('--sortby', help='Column to sort by', default='Datacenter') @environment.pass_env def cli(env, sortby): """List number of block storage volumes limit per datacenter.""" block_manager = SoftLayer.BlockStorageManager(env.client) block_volumes = block_manager.list_block_volume_limit() table = formatting.KeyValueTable(DEFAULT_COLUMNS) table.sortby = sortby for volume in block_volumes: datacenter_name = volume['datacenterName'] maximum_available_count = volume['maximumAvailableCount'] provisioned_count = volume['provisionedCount'] table.add_row([datacenter_name, maximum_available_count, provisioned_count]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/list.py000066400000000000000000000064611437054676600220400ustar00rootroot00000000000000"""List block storage volumes.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import columns as column_helper from SoftLayer.CLI import environment from SoftLayer.CLI import storage_utils COLUMNS = [ column_helper.Column('id', ('id',), mask="id"), column_helper.Column('username', ('username',), mask="username"), column_helper.Column('datacenter', ('serviceResource', 'datacenter', 'name'), mask="serviceResource.datacenter.name"), column_helper.Column( 'storage_type', lambda b: b['storageType']['keyName'].split('_').pop(0) if 'storageType' in b and 'keyName' in b['storageType'] and isinstance(b['storageType']['keyName'], str) else '-', mask="storageType.keyName"), column_helper.Column('capacity_gb', ('capacityGb',), mask="capacityGb"), column_helper.Column('bytes_used', ('bytesUsed',), mask="bytesUsed"), column_helper.Column('IOPs', ('provisionedIops',), mask="provisionedIops"), column_helper.Column('ip_addr', ('serviceResourceBackendIpAddress',), mask="serviceResourceBackendIpAddress"), column_helper.Column('lunId', ('lunId',), mask="lunId"), column_helper.Column('active_transactions', ('activeTransactionCount',), mask="activeTransactionCount"), column_helper.Column('rep_partner_count', ('replicationPartnerCount',), mask="replicationPartnerCount"), column_helper.Column( 'created_by', ('billingItem', 'orderItem', 'order', 'userRecord', 'username')), column_helper.Column('notes', ('notes',), mask="notes"), ] DEFAULT_COLUMNS = [ 'id', 'username', 'datacenter', 'storage_type', 'capacity_gb', 'bytes_used', 'IOPs', 'ip_addr', 'lunId', 'active_transactions', 'rep_partner_count', 'notes' ] @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.option('--username', '-u', help='Volume username') @click.option('--datacenter', '-d', help='Datacenter shortname') @click.option('--order', '-o', type=int, help='Filter by ID of the order that purchased the block storage') @click.option('--storage-type', help='Type of storage volume', type=click.Choice(['performance', 'endurance'])) @click.option('--sortby', help='Column to sort by', default='username') @click.option('--columns', callback=column_helper.get_formatter(COLUMNS), help='Columns to display. Options: {0}'.format( ', '.join(column.name for column in COLUMNS)), default=','.join(DEFAULT_COLUMNS)) @environment.pass_env def cli(env, sortby, columns, datacenter, username, storage_type, order): """List block storage.""" block_manager = SoftLayer.BlockStorageManager(env.client) block_volumes = block_manager.list_block_volumes(datacenter=datacenter, username=username, storage_type=storage_type, order=order, mask=columns.mask()) table = storage_utils.build_output_table(env, block_volumes, columns, sortby) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/lun.py000066400000000000000000000022461437054676600216600ustar00rootroot00000000000000"""Set the LUN ID on an iSCSI volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume-id') @click.argument('lun-id') @environment.pass_env def cli(env, volume_id, lun_id): """Set the LUN ID on an existing block storage volume. The LUN ID only takes effect during the Host Authorization process. It is recommended (but not necessary) to de-authorize all hosts before using this method. See `block access-revoke`. VOLUME_ID - the volume ID on which to set the LUN ID. LUN_ID - recommended range is an integer between 0 and 255. Advanced users can use an integer between 0 and 4095. """ block_storage_manager = SoftLayer.BlockStorageManager(env.client) res = block_storage_manager.create_or_update_lun_id(volume_id, lun_id) if 'value' in res and lun_id == res['value']: click.echo( 'Block volume with id %s is reporting LUN ID %s' % (res['volumeId'], res['value'])) else: click.echo( 'Failed to confirm the new LUN ID on volume %s' % (volume_id)) softlayer-python-6.1.4/SoftLayer/CLI/block/modify.py000066400000000000000000000053071437054676600223520ustar00rootroot00000000000000"""Modify an existing block storage volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()} @click.command(cls=SoftLayer.CLI.command.SLCommand, context_settings=CONTEXT_SETTINGS) @click.argument('volume-id') @click.option('--new-size', '-c', type=int, help='New Size of block volume in GB. ***If no size is given, the original size of volume is used.***\n' 'Potential Sizes: [20, 40, 80, 100, 250, 500, 1000, 2000, 4000, 8000, 12000]\n' 'Minimum: [the original size of the volume]') @click.option('--new-iops', '-i', type=int, help='Performance Storage IOPS, between 100 and 6000 in multiples of 100 [only for performance volumes] ' '***If no IOPS value is specified, the original IOPS value of the volume will be used.***\n' 'Requirements: [If original IOPS/GB for the volume is less than 0.3, new IOPS/GB must also be ' 'less than 0.3. If original IOPS/GB for the volume is greater than or equal to 0.3, new IOPS/GB ' 'for the volume must also be greater than or equal to 0.3.]') @click.option('--new-tier', '-t', help='Endurance Storage Tier (IOPS per GB) [only for endurance volumes] ' '***If no tier is specified, the original tier of the volume will be used.***\n' 'Requirements: [If original IOPS/GB for the volume is 0.25, new IOPS/GB for the volume must also ' 'be 0.25. If original IOPS/GB for the volume is greater than 0.25, new IOPS/GB for the volume ' 'must also be greater than 0.25.]', type=click.Choice(['0.25', '2', '4', '10'])) @environment.pass_env def cli(env, volume_id, new_size, new_iops, new_tier): """Modify an existing block storage volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) if new_tier is not None: new_tier = float(new_tier) try: order = block_manager.order_modified_volume( volume_id, new_size=new_size, new_iops=new_iops, new_tier_level=new_tier, ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) if 'placedOrder' in order.keys(): click.echo("Order #{0} placed successfully!".format(order['placedOrder']['id'])) for item in order['placedOrder']['items']: click.echo(" > %s" % item['description']) else: click.echo("Order could not be placed! Please verify your options and try again.") softlayer-python-6.1.4/SoftLayer/CLI/block/object_list.py000066400000000000000000000017061437054676600233630ustar00rootroot00000000000000"""List cloud object storage volumes.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @environment.pass_env def cli(env): """List cloud block storage.""" block_manager = SoftLayer.BlockStorageManager(env.client) storages = block_manager.get_cloud_list() table = formatting.Table(['Id', 'Account name', 'Description', 'Create Date', 'Type']) for storage in storages: table.add_row([storage.get('id'), storage.get('username'), storage['storageType']['description'], storage['billingItem']['createDate'], storage['storageType']['keyName']]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/object_storage_detail.py000066400000000000000000000023501437054676600253720ustar00rootroot00000000000000"""Display details for a specified cloud object storage.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('object_id') @environment.pass_env def cli(env, object_id): """Display details for a cloud object storage.""" block_manager = SoftLayer.BlockStorageManager(env.client) cloud = block_manager.get_volume_details(object_id) bucket = block_manager.get_buckets(object_id) table = formatting.KeyValueTable(['Name', 'Value']) table.align['Name'] = 'r' table.align['Value'] = 'l' table.add_row(['Id', cloud.get('id')]) table.add_row(['Username', cloud.get('username')]) table.add_row(['Name Service Resource', cloud['serviceResource']['name']]) table.add_row(['Type Service Resource', cloud['serviceResource']['type']['type']]) table.add_row(['Datacenter', cloud['serviceResource']['datacenter']['name']]) table.add_row(['Storage type', cloud['storageType']['keyName']]) table.add_row(['Bytes Used', formatting.b_to_gb(bucket[0]['bytesUsed'])]) table.add_row(['Bucket name', bucket[0]['name']]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/object_storage_permission.py000066400000000000000000000031761437054676600263270ustar00rootroot00000000000000"""Display permission details for a cloud object storage.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('object_id') @environment.pass_env def cli(env, object_id): """Display permission details for a cloud object storage.""" block_manager = SoftLayer.BlockStorageManager(env.client) cloud = block_manager.get_network_message_delivery_accounts(object_id) end_points = block_manager.get_end_points(object_id) table = formatting.Table(['Name', 'Value']) table_credentials = formatting.Table(['Id', 'Access Key ID', 'Secret Access Key', 'Description']) for credential in cloud.get('credentials'): table_credentials.add_row([credential.get('id'), credential.get('username'), credential.get('password'), credential['type']['description']]) table_url = formatting.Table(['Region', 'Location', 'Type', 'URL']) for end_point in end_points: table_url.add_row([end_point.get('region') or '', end_point.get('location') or '', end_point.get('type'), end_point.get('url'), ]) table.add_row(['UUID', cloud.get('uuid')]) table.add_row(['Credentials', table_credentials]) table.add_row(['EndPoint URL´s', table_url]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/options.py000066400000000000000000000113201437054676600225460ustar00rootroot00000000000000"""List all options for ordering a block storage.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI.command import SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions from SoftLayer.CLI import formatting PACKAGE_STORAGE = 759 @click.command(cls=SLCommand) @click.argument('location', required=False) @click.option('--prices', '-p', is_flag=True, help='Use --prices to list the server item prices, and to list the Item Prices by location,' 'add it to the --prices option using location short name, e.g. --prices dal13') @environment.pass_env def cli(env, prices, location=None): """List all options for ordering a block storage""" order_manager = SoftLayer.OrderingManager(env.client) items = order_manager.get_items(PACKAGE_STORAGE) datacenters = order_manager.get_regions(PACKAGE_STORAGE, location) tables = [] network = SoftLayer.NetworkManager(env.client) pods = network.get_closed_pods() if datacenters != []: datacenter_table = formatting.Table(['Id', 'Description', 'KeyName'], title='Datacenter') for datacenter in datacenters: closure = [] for pod in pods: if datacenter['location']['location']['name'] in str(pod['name']): closure.append(pod['name']) notes = '-' if len(closure) > 0: notes = 'closed soon: %s' % (', '.join(closure)) datacenter_table.add_row([datacenter['location']['locationId'], datacenter.get('description'), datacenter['keyname'], notes]) tables.append(datacenter_table) else: raise exceptions.CLIAbort('Location does not exit.') tables.append(_block_ios_get_table(items, prices)) tables.append(_block_storage_table(items, prices)) tables.append(_block_snapshot_get_table(items, prices)) env.fout(tables) def _block_ios_get_table(items, prices): if prices: table = formatting.Table(['Id', 'Description', 'KeyName', 'Prices'], title='IOPS') for block_item in items: if block_item['itemCategory']['categoryCode'] == 'storage_tier_level': table.add_row([block_item.get('id'), block_item.get('description'), block_item.get('keyName'), block_item['prices'][0]['recurringFee']]) else: table = formatting.Table(['Id', 'Description', 'KeyName'], title='IOPS') for block_item in items: if block_item['itemCategory']['categoryCode'] == 'storage_tier_level': table.add_row([block_item.get('id'), block_item.get('description'), block_item.get('keyName')]) table.sortby = 'Id' table.align = 'l' return table def _block_storage_table(items, prices): if prices: table = formatting.Table(['Id', 'Description', 'KeyName', 'Capacity Minimum', 'Prices'], title='Storage') for block_item in items: if block_item['itemCategory']['categoryCode'] == 'performance_storage_space': table.add_row([block_item.get('id'), block_item.get('description'), block_item.get('keyName'), block_item.get('capacityMinimum') or '-', block_item['prices'][0]['recurringFee']]) else: table = formatting.Table(['Id', 'Description', 'KeyName', 'Capacity Minimum'], title='Storage') for block_item in items: if block_item['itemCategory']['categoryCode'] == 'performance_storage_space': table.add_row([block_item.get('id'), block_item.get('description'), block_item.get('keyName'), block_item.get('capacityMinimum') or '-', ]) table.sortby = 'Id' table.align = 'l' return table def _block_snapshot_get_table(items, prices): if prices: table = formatting.Table(['Id', 'Description', 'KeyName', 'Prices'], title='Snapshot') for block_item in items: if block_item['itemCategory']['categoryCode'] == 'storage_snapshot_space': table.add_row([block_item.get('id'), block_item.get('description'), block_item.get('keyName'), block_item['prices'][0]['recurringFee']]) else: table = formatting.Table(['Id', 'Description', 'KeyName'], title='Snapshot') for block_item in items: if block_item['itemCategory']['categoryCode'] == 'storage_snapshot_space': table.add_row([block_item.get('id'), block_item.get('description'), block_item.get('keyName')]) table.sortby = 'Id' table.align = 'l' return table softlayer-python-6.1.4/SoftLayer/CLI/block/order.py000066400000000000000000000122561437054676600221770ustar00rootroot00000000000000"""Order a block storage volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()} @click.command(cls=SoftLayer.CLI.command.SLCommand, context_settings=CONTEXT_SETTINGS) @click.option('--storage-type', help='Type of block storage volume', type=click.Choice(['performance', 'endurance']), required=True) @click.option('--size', type=int, help='Size of block storage volume in GB.', required=True) @click.option('--iops', type=int, help="""Performance Storage IOPs. Options vary based on storage size. [required for storage-type performance]""") @click.option('--tier', help='Endurance Storage Tier (IOP per GB) [required for storage-type endurance]', type=click.Choice(['0.25', '2', '4', '10'])) @click.option('--os-type', help='Operating System', type=click.Choice([ 'HYPER_V', 'LINUX', 'VMWARE', 'WINDOWS_2008', 'WINDOWS_GPT', 'WINDOWS', 'XEN']), required=True) @click.option('--location', help='Datacenter short name (e.g.: dal09)', required=True) @click.option('--snapshot-size', type=int, help='Optional parameter for ordering snapshot ' 'space along with endurance block storage; specifies ' 'the size (in GB) of snapshot space to order') @click.option('--service-offering', help="""The service offering package to use for placing the order. [optional, default is \'storage_as_a_service\']. enterprise and performance are depreciated""", default='storage_as_a_service', type=click.Choice([ 'storage_as_a_service', 'enterprise', 'performance'])) @click.option('--billing', type=click.Choice(['hourly', 'monthly']), default='monthly', help="Optional parameter for Billing rate (default to monthly)") @environment.pass_env def cli(env, storage_type, size, iops, tier, os_type, location, snapshot_size, service_offering, billing): """Order a block storage volume. Valid size and iops options can be found here: https://cloud.ibm.com/docs/BlockStorage/index.html#provisioning-considerations """ block_manager = SoftLayer.BlockStorageManager(env.client) storage_type = storage_type.lower() hourly_billing_flag = False if billing.lower() == "hourly": hourly_billing_flag = True if service_offering != 'storage_as_a_service': click.secho('{} is a legacy storage offering'.format(service_offering), fg='red') if hourly_billing_flag: raise exceptions.CLIAbort( 'Hourly billing is only available for the storage_as_a_service service offering' ) if storage_type == 'performance': if iops is None: raise exceptions.CLIAbort('Option --iops required with Performance') if service_offering == 'performance' and snapshot_size is not None: raise exceptions.CLIAbort( '--snapshot-size is not available for performance service offerings. ' 'Use --service-offering storage_as_a_service' ) try: order = block_manager.order_block_volume( storage_type=storage_type, location=location, size=int(size), iops=iops, os_type=os_type, snapshot_size=snapshot_size, service_offering=service_offering, hourly_billing_flag=hourly_billing_flag ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) if storage_type == 'endurance': if tier is None: raise exceptions.CLIAbort( 'Option --tier required with Endurance in IOPS/GB [0.25,2,4,10]' ) try: order = block_manager.order_block_volume( storage_type=storage_type, location=location, size=int(size), tier_level=float(tier), os_type=os_type, snapshot_size=snapshot_size, service_offering=service_offering, hourly_billing_flag=hourly_billing_flag ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) if 'placedOrder' in order.keys(): click.echo("Order #{0} placed successfully!".format( order['placedOrder']['id'])) for item in order['placedOrder']['items']: click.echo(" > %s" % item['description']) click.echo( '\nYou may run "slcli block volume-list --order {0}" to find this block volume after it ' 'is ready.'.format(order['placedOrder']['id'])) else: click.echo("Order could not be placed! Please verify your options and try again.") softlayer-python-6.1.4/SoftLayer/CLI/block/refresh.py000066400000000000000000000014071437054676600225160ustar00rootroot00000000000000"""Refresh a duplicate volume with a snapshot from its parent.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.argument('snapshot_id') @click.option('--force-refresh', '-f', is_flag=True, default=False, show_default=True, help="Cancel current refresh process and initiates the new refresh.") @environment.pass_env def cli(env, volume_id, snapshot_id, force_refresh): """Refresh a duplicate volume with a snapshot from its parent.""" block_manager = SoftLayer.BlockStorageManager(env.client) resp = block_manager.refresh_dupe(volume_id, snapshot_id, force_refresh) click.echo(resp) softlayer-python-6.1.4/SoftLayer/CLI/block/replication/000077500000000000000000000000001437054676600230155ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/CLI/block/replication/__init__.py000066400000000000000000000000511437054676600251220ustar00rootroot00000000000000"""Block Storage Replication Control.""" softlayer-python-6.1.4/SoftLayer/CLI/block/replication/disaster_recovery_failover.py000066400000000000000000000037271437054676600310230ustar00rootroot00000000000000"""Failover an inaccessible block volume to its available replicant volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, epilog="""Failover an inaccessible block volume to its available replicant volume. If a volume (with replication) becomes inaccessible due to a disaster event, this method can be used to immediately failover to an available replica in another location. This method does not allow for failback via API. After using this method, to failback to the original volume, please open a support ticket. If you wish to test failover, please use replica-failover.""") @click.argument('volume-id') @click.option('--replicant-id', help="ID of the replicant volume.") @environment.pass_env def cli(env, volume_id, replicant_id): """Failover an inaccessible block volume to its available replicant volume.""" block_storage_manager = SoftLayer.BlockStorageManager(env.client) click.secho("""WARNING : Failover an inaccessible block volume to its available replicant volume.""" """If a volume (with replication) becomes inaccessible due to a disaster event,""" """this method can be used to immediately failover to an available replica in another location.""" """This method does not allow for failback via the API.""" """To failback to the original volume after using this method, open a support ticket.""" """If you wish to test failover, use replica-failover instead.""", fg='red') if not formatting.confirm('Are you sure you want to continue?'): raise exceptions.CLIAbort('Aborted.') block_storage_manager.disaster_recovery_failover_to_replicant( volume_id, replicant_id ) click.echo("Disaster Recovery Failover to replicant is now in progress.") softlayer-python-6.1.4/SoftLayer/CLI/block/replication/failback.py000066400000000000000000000012151437054676600251220ustar00rootroot00000000000000"""Failback from a replicant volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume-id') @environment.pass_env def cli(env, volume_id): """Failback a block volume from the given replica volume.""" block_storage_manager = SoftLayer.BlockStorageManager(env.client) success = block_storage_manager.failback_from_replicant(volume_id) if success: click.echo("Failback from replicant is now in progress.") else: click.echo("Failback operation could not be initiated.") softlayer-python-6.1.4/SoftLayer/CLI/block/replication/failover.py000066400000000000000000000013731437054676600252020ustar00rootroot00000000000000"""Failover to a replicant volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume-id') @click.option('--replicant-id', help="ID of the replicant volume.") @environment.pass_env def cli(env, volume_id, replicant_id): """Failover a block volume to the given replica volume.""" block_storage_manager = SoftLayer.BlockStorageManager(env.client) success = block_storage_manager.failover_to_replicant( volume_id, replicant_id ) if success: click.echo("Failover to replicant is now in progress.") else: click.echo("Failover operation could not be initiated.") softlayer-python-6.1.4/SoftLayer/CLI/block/replication/locations.py000066400000000000000000000031521437054676600253630ustar00rootroot00000000000000"""List suitable replication datacenters for the given volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import columns as column_helper from SoftLayer.CLI import environment from SoftLayer.CLI import formatting COLUMNS = [ column_helper.Column('ID', ('id',), mask="id"), column_helper.Column('Long Name', ('longName',), mask="longName"), column_helper.Column('Short Name', ('name',), mask="name"), ] DEFAULT_COLUMNS = [ 'ID', 'Long Name', 'Short Name', ] @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume-id') @click.option('--columns', callback=column_helper.get_formatter(COLUMNS), help='Columns to display. Options: {0}'.format( ', '.join(column.name for column in COLUMNS)), default=','.join(DEFAULT_COLUMNS)) @click.option('--sortby', help='Column to sort by', default='Long Name') @environment.pass_env def cli(env, columns, sortby, volume_id): """List suitable replication datacenters for the given volume.""" block_storage_manager = SoftLayer.BlockStorageManager(env.client) legal_centers = block_storage_manager.get_replication_locations( volume_id ) if not legal_centers: click.echo("No data centers compatible for replication.") else: table = formatting.KeyValueTable(columns.columns) table.sortby = sortby for legal_center in legal_centers: table.add_row([value or formatting.blank() for value in columns.row(legal_center)]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/replication/order.py000066400000000000000000000063141437054676600245060ustar00rootroot00000000000000"""Order a block storage replica volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions from SoftLayer.CLI import helpers from SoftLayer import utils CONTEXT_SETTINGS = {'token_normalize_func': lambda x: x.upper()} @click.command(cls=SoftLayer.CLI.command.SLCommand, context_settings=CONTEXT_SETTINGS) @click.argument('volume_id') @click.option('--datacenter', '-d', help='Short name of the datacenter for the replica (e.g.: dal09)', required=True) @click.option('--iops', '-i', help='Performance Storage IOPs, between 100 and 6000 in multiples of 100. If no IOPS value is specified,' ' the IOPS value of the original volume will be used.', type=int) @click.option('--os-type', '-o', help='Operating System Type (eg. LINUX) of the primary volume for ' 'which a replica is ordered [optional].', type=click.Choice([ 'HYPER_V', 'LINUX', 'VMWARE', 'WINDOWS_2008', 'WINDOWS_GPT', 'WINDOWS', 'XEN'])) @click.option('--snapshot-schedule', '-s', help='Snapshot schedule to use for replication. Options are: ' 'HOURLY, DAILY, WEEKLY', required=True, type=click.Choice(['HOURLY', 'DAILY', 'WEEKLY'])) @click.option('--tier', '-t', help='Endurance Storage Tier (IOPS per GB) of the primary volume for which a replica is ordered ' '[optional]. If no tier is specified, the tier of the original volume will be used', type=click.Choice(['0.25', '2', '4', '10'])) @environment.pass_env def cli(env, volume_id, snapshot_schedule, datacenter, tier, os_type, iops): """Order a block storage replica volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) block_volume_id = helpers.resolve_id(block_manager.resolve_ids, volume_id, 'Block Volume') if tier is not None: tier = float(tier) if iops is not None: if iops < 100 or iops > 6000: raise exceptions.ArgumentError(f"Invalid value for '--iops' / '-i': '{iops}' is not one " "of between 100 and 6000.") if iops % 100 != 0: raise exceptions.ArgumentError(f"Invalid value for '--iops' / '-i': '{iops}' is not a multiple of 100.") try: order = block_manager.order_replicant_volume( block_volume_id, snapshot_schedule=snapshot_schedule, location=datacenter, tier=tier, os_type=os_type, iops=iops ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) if 'placedOrder' in order.keys(): click.echo("Order #{0} placed successfully!".format( utils.lookup(order, 'placedOrder', 'id'))) for item in utils.lookup(order, 'placedOrder', 'items'): click.echo(" > %s" % item.get('description')) else: click.echo("Order could not be placed! Please verify your options " + "and try again.") softlayer-python-6.1.4/SoftLayer/CLI/block/replication/partners.py000066400000000000000000000027451437054676600252350ustar00rootroot00000000000000"""List existing replicant volumes for a block volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import columns as column_helper from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.CLI import storage_utils COLUMNS = storage_utils.REPLICATION_PARTNER_COLUMNS DEFAULT_COLUMNS = storage_utils.REPLICATION_PARTNER_DEFAULT @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume-id') @click.option('--columns', callback=column_helper.get_formatter(COLUMNS), help='Columns to display. Options: {0}'.format( ', '.join(column.name for column in COLUMNS)), default=','.join(DEFAULT_COLUMNS)) @click.option('--sortby', help='Column to sort by', default='Username') @environment.pass_env def cli(env, columns, sortby, volume_id): """List existing replica volumes for a block volume.""" block_storage_manager = SoftLayer.BlockStorageManager(env.client) legal_volumes = block_storage_manager.get_replication_partners( volume_id ) if not legal_volumes: click.echo("There are no replication partners for the given volume.") else: table = formatting.Table(columns.columns) table.sortby = sortby for legal_volume in legal_volumes: table.add_row([value or formatting.blank() for value in columns.row(legal_volume)]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/set_note.py000066400000000000000000000016371437054676600227050ustar00rootroot00000000000000"""Set note for an existing block storage volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import helpers @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume-id') @click.option('--note', '-n', type=str, required=True, help='Public notes related to a Storage volume') @environment.pass_env def cli(env, volume_id, note): """Set note for an existing block storage volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) block_volume_id = helpers.resolve_id(block_manager.resolve_ids, volume_id, 'Block Volume') result = block_manager.volume_set_note(block_volume_id, note) if result: click.echo("Set note successfully!") else: click.echo("Note could not be set! Please verify your options and try again.") softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/000077500000000000000000000000001437054676600223435ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/__init__.py000066400000000000000000000000461437054676600244540ustar00rootroot00000000000000"""Block Storage Snapshot Control.""" softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/cancel.py000066400000000000000000000026241437054676600241460ustar00rootroot00000000000000"""Cancel a snapshot space subscription.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume-id') @click.option('--reason', help="An optional reason for cancellation") @click.option('--immediate', is_flag=True, help="Cancels the snapshot space immediately instead " "of on the billing anniversary") @environment.pass_env def cli(env, volume_id, reason, immediate): """Cancel existing snapshot space for a given volume.""" block_storage_manager = SoftLayer.BlockStorageManager(env.client) if not (env.skip_confirmations or formatting.no_going_back(volume_id)): raise exceptions.CLIAbort('Aborted') cancelled = block_storage_manager.cancel_snapshot_space( volume_id, reason, immediate) if cancelled: if immediate: click.echo('Block volume with id %s has been marked' ' for immediate snapshot cancellation' % volume_id) else: click.echo('Block volume with id %s has been marked' ' for snapshot cancellation' % volume_id) else: click.echo('Unable to cancel snapshot space for block volume %s' % volume_id) softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/create.py000066400000000000000000000015331437054676600241620ustar00rootroot00000000000000"""Create a block storage snapshot.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option('--notes', '-n', help='Notes to set on the new snapshot') @environment.pass_env def cli(env, volume_id, notes): """Creates a snapshot on a given volume""" block_manager = SoftLayer.BlockStorageManager(env.client) snapshot = block_manager.create_snapshot(volume_id, notes=notes) if 'id' in snapshot: click.echo('New snapshot created with id: %s' % snapshot['id']) else: click.echo('Error occurred while creating snapshot.\n' 'Ensure volume is not failed over or in another ' 'state which prevents taking snapshots.') softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/delete.py000066400000000000000000000010221437054676600241520ustar00rootroot00000000000000"""Delete a block storage snapshot.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('snapshot_id') @environment.pass_env def cli(env, snapshot_id): """Deletes a snapshot on a given volume""" block_manager = SoftLayer.BlockStorageManager(env.client) deleted = block_manager.delete_snapshot(snapshot_id) if deleted: click.echo('Snapshot %s deleted' % snapshot_id) softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/disable.py000066400000000000000000000017671437054676600243330ustar00rootroot00000000000000"""Disable scheduled snapshots of a specific volume""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option('--schedule-type', help='Snapshot schedule [INTERVAL|HOURLY|DAILY|WEEKLY]', required=True) @environment.pass_env def cli(env, volume_id, schedule_type): """Disables snapshots on the specified schedule for a given volume""" if (schedule_type not in ['INTERVAL', 'HOURLY', 'DAILY', 'WEEKLY']): raise exceptions.CLIAbort( '--schedule-type must be INTERVAL, HOURLY, DAILY, or WEEKLY') block_manager = SoftLayer.BlockStorageManager(env.client) disabled = block_manager.disable_snapshots(volume_id, schedule_type) if disabled: click.echo('%s snapshots have been disabled for volume %s' % (schedule_type, volume_id)) softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/enable.py000066400000000000000000000045321437054676600241470ustar00rootroot00000000000000# snapshot_enable.py """Create a block storage snapshot [ENABLE].""" import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option('--schedule-type', help='Snapshot schedule [INTERVAL|HOURLY|DAILY|WEEKLY]', required=True) @click.option('--retention-count', help='Number of snapshots to retain', required=True) @click.option('--minute', help='Minute of the day when snapshots should be taken', default=0) @click.option('--hour', help='Hour of the day when snapshots should be taken', default=0) @click.option('--day-of-week', help='Day of the week when snapshots should be taken', default='SUNDAY') @environment.pass_env def cli(env, volume_id, schedule_type, retention_count, minute, hour, day_of_week): """Enables snapshots for a given volume on the specified schedule""" block_manager = SoftLayer.BlockStorageManager(env.client) valid_schedule_types = {'INTERVAL', 'HOURLY', 'DAILY', 'WEEKLY'} valid_days = {'SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY'} if schedule_type not in valid_schedule_types: raise exceptions.CLIAbort( '--schedule-type must be INTERVAL, HOURLY, DAILY,' + 'or WEEKLY, not ' + schedule_type) if schedule_type == 'INTERVAL' and (minute < 30 or minute > 59): raise exceptions.CLIAbort( '--minute value must be between 30 and 59') if minute < 0 or minute > 59: raise exceptions.CLIAbort( '--minute value must be between 0 and 59') if hour < 0 or hour > 23: raise exceptions.CLIAbort( '--hour value must be between 0 and 23') if day_of_week not in valid_days: raise exceptions.CLIAbort( '--day_of_week value must be a valid day (ex: SUNDAY)') enabled = block_manager.enable_snapshots(volume_id, schedule_type, retention_count, minute, hour, day_of_week) if enabled: click.echo('%s snapshots have been enabled for volume %s' % (schedule_type, volume_id)) softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/get_notify_status.py000066400000000000000000000014501437054676600264670ustar00rootroot00000000000000"""Get the snapshots space usage threshold warning flag setting for specific volume""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @environment.pass_env def cli(env, volume_id): """Get snapshots space usage threshold warning flag setting for a given volume""" block_manager = SoftLayer.BlockStorageManager(env.client) enabled = block_manager.get_volume_snapshot_notification_status(volume_id) if enabled == 0: click.echo("Disabled: Snapshots space usage threshold is disabled for volume {}".format(volume_id)) else: click.echo("Enabled: Snapshots space usage threshold is enabled for volume {}".format(volume_id)) softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/list.py000066400000000000000000000033441437054676600236740ustar00rootroot00000000000000"""List block storage snapshots.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import columns as column_helper from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.CLI import helpers COLUMNS = [ column_helper.Column('id', ('id',), mask='id'), column_helper.Column('name', ('notes',), mask='notes'), column_helper.Column('created', ('snapshotCreationTimestamp',), mask='snapshotCreationTimestamp'), column_helper.Column('size_bytes', ('snapshotSizeBytes',), mask='snapshotSizeBytes'), ] DEFAULT_COLUMNS = [ 'id', 'name', 'created', 'size_bytes' ] @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option('--sortby', help='Column to sort by', default='created') @click.option('--columns', callback=column_helper.get_formatter(COLUMNS), help='Columns to display. Options: {0}'.format( ', '.join(column.name for column in COLUMNS)), default=','.join(DEFAULT_COLUMNS)) @environment.pass_env def cli(env, volume_id, sortby, columns): """List block storage snapshots.""" block_manager = SoftLayer.BlockStorageManager(env.client) resolved_id = helpers.resolve_id(block_manager.resolve_ids, volume_id, 'Volume Id') snapshots = block_manager.get_block_volume_snapshot_list( resolved_id, mask=columns.mask() ) table = formatting.Table(columns.columns) table.sortby = sortby for snapshot in snapshots: table.add_row([value or formatting.blank() for value in columns.row(snapshot)]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/order.py000066400000000000000000000035461437054676600240400ustar00rootroot00000000000000"""Order snapshot space for a block storage volume.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option('--capacity', type=int, help='Size of snapshot space to create in GB', required=True) @click.option('--tier', help='Endurance Storage Tier (IOPS per GB) of the block' ' volume for which space is ordered [optional, and only' ' valid for endurance storage volumes]', type=click.Choice(['0.25', '2', '4', '10'])) @click.option('--upgrade', type=bool, help='Flag to indicate that the order is an upgrade', default=False, is_flag=True) @environment.pass_env def cli(env, volume_id, capacity, tier, upgrade): """Order snapshot space for a block storage volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) if tier is not None: tier = float(tier) try: order = block_manager.order_snapshot_space( volume_id, capacity=capacity, tier=tier, upgrade=upgrade ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) if 'placedOrder' in order.keys(): click.echo("Order #{0} placed successfully!".format( order['placedOrder']['id'])) for item in order['placedOrder']['items']: click.echo(" > %s" % item['description']) if 'status' in order['placedOrder'].keys(): click.echo(" > Order status: %s" % order['placedOrder']['status']) else: click.echo("Order could not be placed! Please verify your options " + "and try again.") softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/restore.py000066400000000000000000000014141437054676600244000ustar00rootroot00000000000000"""Restore a block volume from a snapshot.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option('--snapshot-id', '-s', help='The id of the snapshot which will be used' ' to restore the block volume') @environment.pass_env def cli(env, volume_id, snapshot_id): """Restore block volume using a given snapshot""" block_manager = SoftLayer.BlockStorageManager(env.client) success = block_manager.restore_from_snapshot(volume_id, snapshot_id) if success: click.echo('Block volume %s is being restored using snapshot %s' % (volume_id, snapshot_id)) softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/schedule_list.py000066400000000000000000000045511437054676600255510ustar00rootroot00000000000000"""List scheduled snapshots of a specific volume""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @environment.pass_env def cli(env, volume_id): """Lists snapshot schedules for a given volume""" block_manager = SoftLayer.BlockStorageManager(env.client) snapshot_schedules = block_manager.list_volume_schedules(volume_id) table = formatting.Table(['id', 'active', 'type', 'replication', 'date_created', 'minute', 'hour', 'day', 'week', 'day_of_week', 'date_of_month', 'month_of_year', 'maximum_snapshots']) for schedule in snapshot_schedules: if 'REPLICATION' in schedule['type']['keyname']: replication = '*' else: replication = formatting.blank() block_schedule_type = schedule['type']['keyname'].replace('REPLICATION_', '') block_schedule_type = block_schedule_type.replace('SNAPSHOT_', '') property_list = ['MINUTE', 'HOUR', 'DAY', 'WEEK', 'DAY_OF_WEEK', 'DAY_OF_MONTH', 'MONTH_OF_YEAR', 'SNAPSHOT_LIMIT'] schedule_properties = [] for prop_key in property_list: item = formatting.blank() for schedule_property in schedule.get('properties', []): if schedule_property['type']['keyname'] == prop_key: if schedule_property['value'] == '-1': item = '*' else: item = schedule_property['value'] break schedule_properties.append(item) table_row = [ schedule['id'], '*' if schedule.get('active', '') else '', block_schedule_type, replication, schedule.get('createDate', '')] table_row.extend(schedule_properties) table.add_row(table_row) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/block/snapshot/set_notify_status.py000066400000000000000000000016661437054676600265140ustar00rootroot00000000000000"""Disable/Enable snapshots space usage threshold warning for a specific volume""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('volume_id') @click.option( '--enable/--disable', default=True, help=""" Enable/Disable snapshot notification. Use `slcli block snapshot-set-notification volumeId --enable` to enable """, required=True) @environment.pass_env def cli(env, volume_id, enable): """Enables/Disables snapshot space usage threshold warning for a given volume""" block_manager = SoftLayer.BlockStorageManager(env.client) status = block_manager.set_volume_snapshot_notification(volume_id, enable) if status: click.echo( 'Snapshots space usage threshold warning notification has bee set to %s for volume %s' % (enable, volume_id)) softlayer-python-6.1.4/SoftLayer/CLI/block/subnets/000077500000000000000000000000001437054676600221675ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/CLI/block/subnets/__init__.py000066400000000000000000000000451437054676600242770ustar00rootroot00000000000000"""Block Storage Subnets Control.""" softlayer-python-6.1.4/SoftLayer/CLI/block/subnets/assign.py000066400000000000000000000027121437054676600240270ustar00rootroot00000000000000"""Assign block storage subnets to the given host id.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('access_id', type=int) @click.option('--subnet-id', multiple=True, type=int, help="ID of the subnets to assign; e.g.: --subnet-id 1234") @environment.pass_env def cli(env, access_id, subnet_id): """Assign block storage subnets to the given host id. access_id is the host_id obtained by: slcli block access-list SoftLayer_Account::iscsiisolationdisabled must be False to use this command """ try: subnet_ids = list(subnet_id) block_manager = SoftLayer.BlockStorageManager(env.client) assigned_subnets = block_manager.assign_subnets_to_acl(access_id, subnet_ids) for subnet in assigned_subnets: message = "Successfully assigned subnet id: {} to allowed host id: {}".format(subnet, access_id) click.echo(message) failed_to_assign_subnets = list(set(subnet_ids) - set(assigned_subnets)) for subnet in failed_to_assign_subnets: message = "Failed to assign subnet id: {} to allowed host id: {}".format(subnet, access_id) click.echo(message) except SoftLayer.SoftLayerAPIError as ex: message = "Unable to assign subnets.\nReason: {}".format(ex.faultString) click.echo(message) softlayer-python-6.1.4/SoftLayer/CLI/block/subnets/list.py000066400000000000000000000024511437054676600235160ustar00rootroot00000000000000"""List block storage assigned subnets for the given host id.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.CLI import helpers COLUMNS = [ 'id', 'networkIdentifier', 'cidr' ] @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('access_id', type=int) @environment.pass_env def cli(env, access_id): """List block storage assigned subnets for the given host id. access_id is the host_id obtained by: slcli block access-list """ try: block_manager = SoftLayer.BlockStorageManager(env.client) resolved_id = helpers.resolve_id(block_manager.resolve_ids, access_id, 'Volume Id') subnets = block_manager.get_subnets_in_acl(resolved_id) table = formatting.Table(COLUMNS) for subnet in subnets: row = ["{0}".format(subnet['id']), "{0}".format(subnet['networkIdentifier']), "{0}".format(subnet['cidr'])] table.add_row(row) env.fout(table) except SoftLayer.SoftLayerAPIError as ex: message = "Unable to list assigned subnets for access-id: {}.\nReason: {}".format(access_id, ex.faultString) click.echo(message) softlayer-python-6.1.4/SoftLayer/CLI/block/subnets/remove.py000066400000000000000000000027141437054676600240420ustar00rootroot00000000000000"""Remove block storage subnets for the given host id.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('access_id', type=int) @click.option('--subnet-id', multiple=True, type=int, help="ID of the subnets to remove; e.g.: --subnet-id 1234") @environment.pass_env def cli(env, access_id, subnet_id): """Remove block storage subnets for the given host id. access_id is the host_id obtained by: slcli block access-list SoftLayer_Account::iscsiisolationdisabled must be False to use this command """ try: subnet_ids = list(subnet_id) block_manager = SoftLayer.BlockStorageManager(env.client) removed_subnets = block_manager.remove_subnets_from_acl(access_id, subnet_ids) for subnet in removed_subnets: message = "Successfully removed subnet id: {} for allowed host id: {}".format(subnet, access_id) click.echo(message) failed_to_remove_subnets = list(set(subnet_ids) - set(removed_subnets)) for subnet in failed_to_remove_subnets: message = "Failed to remove subnet id: {} for allowed host id: {}".format(subnet, access_id) click.echo(message) except SoftLayer.SoftLayerAPIError as ex: message = "Unable to remove subnets.\nReason: {}".format(ex.faultString) click.echo(message) softlayer-python-6.1.4/SoftLayer/CLI/call_api.py000066400000000000000000000162411437054676600215340ustar00rootroot00000000000000"""Call arbitrary API endpoints.""" import json import click from SoftLayer.CLI.command import SLCommand as SLCommand from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions from SoftLayer.CLI import formatting from SoftLayer.CLI import helpers from SoftLayer import utils SPLIT_TOKENS = [ ('in', ' IN '), ('eq', '='), ] def _build_filters(_filters): """Builds filters using the filter options passed into the CLI. This only supports the equals keyword at the moment. """ root = utils.NestedDict({}) for _filter in _filters: operation = None for operation, token in SPLIT_TOKENS: # split "some.key=value" into ["some.key", "value"] top_parts = _filter.split(token, 1) if len(top_parts) == 2: break else: raise exceptions.CLIAbort('Failed to find valid operation for: %s' % _filter) key, value = top_parts current = root # split "some.key" into ["some", "key"] parts = [part.strip() for part in key.split('.')] # Actually drill down and add the filter for part in parts[:-1]: current = current[part] if operation == 'eq': current[parts[-1]] = utils.query_filter(value.strip()) elif operation == 'in': current[parts[-1]] = { 'operation': 'in', 'options': [{ 'name': 'data', 'value': [p.strip() for p in value.split(',')], }], } return root.to_dict() def _build_python_example(args, kwargs): sorted_kwargs = sorted(kwargs.items()) call_str = 'import SoftLayer\n\n' call_str += 'client = SoftLayer.create_client_from_env()\n' call_str += 'result = client.call(' arg_list = [repr(arg) for arg in args] arg_list += [key + '=' + repr(value) for key, value in sorted_kwargs if value] call_str += ',\n '.join(arg_list) call_str += ')' return call_str def _validate_filter(ctx, param, value): # pylint: disable=unused-argument """Validates a JSON style object filter""" _filter = None if value: try: _filter = json.loads(value) if not isinstance(_filter, dict): raise exceptions.CLIAbort("\"{}\" should be a JSON object, but is a {} instead.". format(_filter, type(_filter))) except json.JSONDecodeError as error: raise exceptions.CLIAbort("\"{}\" is not valid JSON. {}".format(value, error)) return _filter def _validate_parameters(ctx, param, value): # pylint: disable=unused-argument """Checks if value is a JSON string, and converts it to a datastructure if that is true""" validated_values = [] for parameter in value: if isinstance(parameter, str): # looks like a JSON string... if '{' in parameter or '[' in parameter: try: parameter = json.loads(parameter) except json.JSONDecodeError as error: click.secho("{} looked like json, but was invalid, passing to API as is. {}". format(parameter, error), fg='red') validated_values.append(parameter) return validated_values @click.command('call', short_help="Call arbitrary API endpoints.", cls=SLCommand) @click.argument('service') @click.argument('method') @click.argument('parameters', nargs=-1, callback=_validate_parameters) @click.option('--id', '_id', help="Init parameter") @helpers.multi_option('--filter', '-f', '_filters', help="Object filters. This should be of the form: 'property=value' or 'nested.property=value'." "Complex filters should use --json-filter.") @click.option('--mask', help="String-based object mask") @click.option('--limit', type=click.INT, help="Result limit") @click.option('--offset', type=click.INT, help="Result offset") @click.option('--orderBy', type=click.STRING, help="To set the sort direction, ASC or DESC can be provided." "This should be of the form: '--orderBy nested.property' default DESC or " "'--orderBy nested.property=ASC', e.g. " " --orderBy subnets.id default DESC" " --orderBy subnets.id=ASC") @click.option('--output-python / --no-output-python', help="Show python example code instead of executing the call") @click.option('--json-filter', callback=_validate_filter, help="A JSON string to be passed in as the object filter to the API call. " "Remember to use double quotes (\") for variable names. Can NOT be used with --filter. " "Dont use whitespace outside of strings, or the slcli might have trouble parsing it.") @environment.pass_env def cli(env, service, method, parameters, _id, _filters, mask, limit, offset, orderby=None, output_python=False, json_filter=None): """Call arbitrary API endpoints with the given SERVICE and METHOD. For parameters that require a datatype, use a JSON string for that parameter. Example:: slcli call-api Account getObject slcli call-api Account getVirtualGuests --limit=10 --mask=id,hostname slcli call-api Virtual_Guest getObject --id=12345 slcli call-api Metric_Tracking_Object getBandwidthData --id=1234 \\ "2015-01-01 00:00:00" "2015-01-1 12:00:00" public slcli call-api Account getVirtualGuests \\ -f 'virtualGuests.datacenter.name=dal05' \\ -f 'virtualGuests.maxCpu=4' \\ --mask=id,hostname,datacenter.name,maxCpu slcli call-api Account getVirtualGuests \\ -f 'virtualGuests.datacenter.name IN dal05,sng01' slcli call-api Account getVirtualGuests \\ --json-filter '{"virtualGuests":{"hostname":{"operation":"^= test"}}}' --limit=10 slcli -v call-api SoftLayer_User_Customer addBulkPortalPermission --id=1234567 \\ '[{"keyName": "NETWORK_MESSAGE_DELIVERY_MANAGE"}]' slcli call-api Account getVirtualGuests \\ --orderBy virttualguests.id=ASC slcli call-api SoftLayer_Notification_Occurrence_Event getAllObjects \\ --json-filter='{"endDate": {"operation": "greaterThanDate", \\ "options": [{"name":"date", "value": ["10/14/2022"]}]}}' --limit=50 """ if _filters and json_filter: raise exceptions.CLIAbort("--filter and --json-filter cannot be used together.") object_filter = _build_filters(_filters) if orderby: orderby = utils.build_filter_orderby(orderby) object_filter = utils.dict_merge(object_filter, orderby) if json_filter: object_filter = utils.dict_merge(json_filter, object_filter) args = [service, method] + list(parameters) kwargs = { 'id': _id, 'filter': object_filter, 'mask': mask, 'limit': limit, 'offset': offset, } if output_python: env.python_output(_build_python_example(args, kwargs)) else: result = env.client.call(*args, **kwargs) env.fout(formatting.iter_to_table(result)) softlayer-python-6.1.4/SoftLayer/CLI/cdn/000077500000000000000000000000001437054676600201565ustar00rootroot00000000000000softlayer-python-6.1.4/SoftLayer/CLI/cdn/__init__.py000066400000000000000000000001171437054676600222660ustar00rootroot00000000000000"""Content Delivery Network.""" # :license: MIT, see LICENSE for more details. softlayer-python-6.1.4/SoftLayer/CLI/cdn/detail.py000066400000000000000000000031171437054676600217740ustar00rootroot00000000000000"""Detail a CDN Account.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('unique_id') @click.option('--history', default=30, type=click.IntRange(1, 89), help='Bandwidth, Hits, Ratio counted over history number of days ago. 89 is the maximum. ') @environment.pass_env def cli(env, unique_id, history): """Detail a CDN Account.""" manager = SoftLayer.CDNManager(env.client) cdn_mapping = manager.get_cdn(unique_id) cdn_metrics = manager.get_usage_metrics(unique_id, history=history) # usage metrics total_bandwidth = "%s GB" % cdn_metrics['totals'][0] total_hits = cdn_metrics['totals'][1] hit_ratio = "%s %%" % cdn_metrics['totals'][2] table = formatting.KeyValueTable(['name', 'value']) table.align['name'] = 'r' table.align['value'] = 'l' table.add_row(['unique_id', cdn_mapping['uniqueId']]) table.add_row(['hostname', cdn_mapping['domain']]) table.add_row(['protocol', cdn_mapping['protocol']]) table.add_row(['origin', cdn_mapping['originHost']]) table.add_row(['origin_type', cdn_mapping['originType']]) table.add_row(['path', cdn_mapping['path']]) table.add_row(['provider', cdn_mapping['vendorName']]) table.add_row(['status', cdn_mapping['status']]) table.add_row(['total_bandwidth', total_bandwidth]) table.add_row(['total_hits', total_hits]) table.add_row(['hit_ratio', hit_ratio]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/cdn/edit.py000066400000000000000000000072641437054676600214660ustar00rootroot00000000000000"""Edit a CDN Account.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.CLI import helpers @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('identifier') @click.option('--header', '-H', type=click.STRING, help="Host header." ) @click.option('--http-port', '-t', type=click.INT, help="HTTP port." ) @click.option('--https-port', '-s', type=click.INT, help="HTTPS port." ) @click.option('--origin', '-o', type=click.STRING, help="Origin server address." ) @click.option('--respect-headers', '-r', type=click.Choice(['1', '0']), help="Respect headers. The value 1 is On and 0 is Off." ) @click.option('--cache', '-c', multiple=True, type=str, help="Cache key optimization. These are the valid options to choose: 'include-all', 'ignore-all', " "'include-specified', 'ignore-specified'. If you select 'include-specified' or 'ignore-specified' " "please add a description too using again --cache, " "e.g --cache=include-specified --cache=description." ) @click.option('--performance-configuration', '-p', type=click.Choice(['General web delivery', 'Large file optimization', 'Video on demand optimization']), help="Optimize for, General web delivery', 'Large file optimization', 'Video on demand optimization', " "the Dynamic content acceleration option is not added because this has a special configuration." ) @environment.pass_env def cli(env, identifier, header, http_port, https_port, origin, respect_headers, cache, performance_configuration): """Edit a CDN Account. Note: You can use the hostname or uniqueId as IDENTIFIER. """ manager = SoftLayer.CDNManager(env.client) cdn_id = helpers.resolve_id(manager.resolve_ids, identifier, 'CDN') cache_result = {} if cache: if len(cache) > 1: cache_result['cacheKeyQueryRule'] = cache[0] cache_result['description'] = cache[1] else: cache_result['cacheKeyQueryRule'] = cache[0] cdn_result = manager.edit(cdn_id, header=header, http_port=http_port, https_port=https_port, origin=origin, respect_headers=respect_headers, cache=cache_result, performance_configuration=performance_configuration) table = formatting.KeyValueTable(['name', 'value']) table.align['name'] = 'r' table.align['value'] = 'l' for cdn in cdn_result: table.add_row(['Create Date', cdn.get('createDate')]) table.add_row(['Header', cdn.get('header')]) if cdn.get('httpPort'): table.add_row(['Http Port', cdn.get('httpPort')]) if cdn.get('httpsPort'): table.add_row(['Https Port', cdn.get('httpsPort')]) table.add_row(['Origin Type', cdn.get('originType')]) table.add_row(['Performance Configuration', cdn.get('performanceConfiguration')]) table.add_row(['Protocol', cdn.get('protocol')]) table.add_row(['Respect Headers', cdn.get('respectHeaders')]) table.add_row(['Unique Id', cdn.get('uniqueId')]) table.add_row(['Vendor Name', cdn.get('vendorName')]) table.add_row(['Cache key optimization', cdn.get('cacheKeyQueryRule')]) table.add_row(['cname', cdn.get('cname')]) table.add_row(['Origin server address', cdn.get('originHost')]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/cdn/list.py000066400000000000000000000023671437054676600215130ustar00rootroot00000000000000"""List CDN Accounts.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.option('--sortby', help='Column to sort by', type=click.Choice(['unique_id', 'domain', 'origin', 'vendor', 'cname', 'status'])) @environment.pass_env def cli(env, sortby): """List all CDN accounts.""" manager = SoftLayer.CDNManager(env.client) accounts = manager.list_cdn() table = formatting.Table(['unique_id', 'domain', 'origin', 'vendor', 'cname', 'status']) for account in accounts: table.add_row([ account['uniqueId'], account['domain'], account['originHost'], account['vendorName'], account['cname'], account['status'] ]) table.sortby = sortby env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/cdn/origin_add.py000066400000000000000000000065271437054676600226410ustar00rootroot00000000000000"""Create an origin pull mapping.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import exceptions from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('unique_id') @click.argument('origin') @click.argument('path') @click.option('--origin-type', '-t', type=click.Choice(['server', 'storage']), help='The origin type.', default='server', show_default=True) @click.option('--header', '-H', type=click.STRING, help='The host header to communicate with the origin.') @click.option('--bucket-name', '-b', type=click.STRING, help="The name of the available resource [required if --origin-type=storage]") @click.option('--port', '-p', type=click.INT, help="The http port number.", default=80, show_default=True) @click.option('--protocol', '-P', type=click.STRING, help="The protocol used by the origin.", default='http', show_default=True) @click.option('--optimize-for', '-o', type=click.Choice(['web', 'video', 'file']), help="Performance configuration", default='web', show_default=True) @click.option('--extensions', '-e', type=click.STRING, help="File extensions that can be stored in the CDN, example: 'jpg, png, pdf'") @click.option('--cache-query', '-c', type=click.STRING, help="Cache query rules with the following formats:\n" "'ignore-all', 'include: ', 'ignore: '", default="include-all", show_default=True) @environment.pass_env def cli(env, unique_id, origin, path, origin_type, header, bucket_name, port, protocol, optimize_for, extensions, cache_query): """Create an origin path for an existing CDN mapping. For more information see the following documentation: \n https://cloud.ibm.com/docs/infrastructure/CDN?topic=CDN-manage-your-cdn#adding-origin-path-details """ manager = SoftLayer.CDNManager(env.client) if origin_type == 'storage' and not bucket_name: raise exceptions.ArgumentError('[-b | --bucket-name] is required when [-t | --origin-type] is "storage"') result = manager.add_origin(unique_id, origin, path, origin_type=origin_type, header=header, port=port, protocol=protocol, bucket_name=bucket_name, file_extensions=extensions, optimize_for=optimize_for, cache_query=cache_query) table = formatting.Table(['Item', 'Value']) table.align['Item'] = 'r' table.align['Value'] = 'r' table.add_row(['CDN Unique ID', result['mappingUniqueId']]) if origin_type == 'storage': table.add_row(['Bucket Name', result['bucketName']]) table.add_row(['Origin', result['origin']]) table.add_row(['Origin Type', result['originType']]) table.add_row(['Path', result['path']]) table.add_row(['Port', result['httpPort']]) table.add_row(['Configuration', result['performanceConfiguration']]) table.add_row(['Status', result['status']]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/cdn/origin_list.py000066400000000000000000000013631437054676600230550ustar00rootroot00000000000000"""List origin pull mappings.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('unique_id') @environment.pass_env def cli(env, unique_id): """List origin path for an existing CDN mapping.""" manager = SoftLayer.CDNManager(env.client) origins = manager.get_origins(unique_id) table = formatting.Table(['Path', 'Origin', 'HTTP Port', 'Status']) for origin in origins: table.add_row([origin['path'], origin['origin'], origin['httpPort'], origin['status']]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/cdn/origin_remove.py000066400000000000000000000010751437054676600233770ustar00rootroot00000000000000"""Remove an origin pull mapping.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('unique_id') @click.argument('origin_path') @environment.pass_env def cli(env, unique_id, origin_path): """Removes an origin path for an existing CDN mapping.""" manager = SoftLayer.CDNManager(env.client) manager.remove_origin(unique_id, origin_path) click.secho("Origin with path %s has been deleted" % origin_path, fg='green') softlayer-python-6.1.4/SoftLayer/CLI/cdn/purge.py000066400000000000000000000020071437054676600216510ustar00rootroot00000000000000"""Purge cached files from all edge nodes.""" # :license: MIT, see LICENSE for more details. import click import SoftLayer from SoftLayer.CLI import environment from SoftLayer.CLI import formatting @click.command(cls=SoftLayer.CLI.command.SLCommand, ) @click.argument('unique_id') @click.argument('path') @environment.pass_env def cli(env, unique_id, path): """Creates a purge record and also initiates the purge call. Example: slcli cdn purge 9779455 /article/file.txt For more information see the following documentation: \n https://cloud.ibm.com/docs/infrastructure/CDN?topic=CDN-manage-your-cdn#purging-cached-content """ manager = SoftLayer.CDNManager(env.client) result = manager.purge_content(unique_id, path) table = formatting.Table(['Date', 'Path', 'Saved', 'Status']) for data in result: table.add_row([ data['date'], data['path'], data['saved'], data['status'] ]) env.fout(table) softlayer-python-6.1.4/SoftLayer/CLI/columns.py000066400000000000000000000044011437054676600214430ustar00rootroot00000000000000""" SoftLayer.CLI.columns ~~~~~~~~~~~~~~~~~~~~~~ Utilties for user-defined columns :license: MIT, see LICENSE for more details. """ import click from SoftLayer import utils # pylint: disable=unused-argument class Column(object): """Column desctribes an attribute and how to fetch/display it.""" def __init__(self, name, path, mask=None): self.name = name self.path = path self.mask = mask # If the mask is not set explicitly, infer it from the path if self.mask is None and isinstance(path, (tuple, list)): self.mask = '.'.join(path) class ColumnFormatter(object): """Maps each column using a function""" def __init__(self): self.columns = [] self.column_funcs = [] self.mask_parts = set() def add_column(self, column): """Add a new column along with a formatting function.""" self.columns.append(column.name) self.column_funcs.append(column.path) if column.mask is not None: self.mask_parts.add(column.mask) def row(self, data): """Return a formatted row for the given data.""" for column in self.column_funcs: if callable(column): yield column(data) else: yield utils.lookup(data, *column) def mask(self): """Returns a SoftLayer mask to fetch data needed for each column.""" return ','.join(self.mask_parts) def get_formatter(columns): """This function returns a callback to use with click options. The returned function parses a comma-separated value and returns a new ColumnFormatter. :param columns: a list of Column instances """ column_map = dict((column.name, column) for column in columns) def validate(ctx, param, value): """Click validation function.""" if value == '': raise click.BadParameter('At least one column is required.') formatter = ColumnFormatter() for column in [col.strip() for col in value.split(',')]: if column in column_map: formatter.add_column(column_map[column]) else: formatter.add_column(Column(column, column.split('.'))) return formatter return validate softlayer-python-6.1.4/SoftLayer/CLI/command.py000066400000000000000000000211321437054676600214010ustar00rootroot00000000000000""" SoftLayer.CLI.command ~~~~~~~~~~~~~~~~~~~~~ Command interface for the SoftLayer CLI. Basically the Click commands, with fancy help text :license: MIT, see LICENSE for more details. """ import inspect import types import click from rich import box from rich.highlighter import RegexHighlighter from rich.table import Table from rich.text import Text from SoftLayer.CLI import environment class OptionHighlighter(RegexHighlighter): """Provides highlighter regex for the Command help. Defined in SoftLayer\\utils.py console_color_themes() """ highlights = [ r"(?P^\-\w)", # single options like -v r"(?P