Merge branch 'trunk' of https://github.com/jwk404/libcloud into jwk404-trunk
diff --git a/.asf.yaml b/.asf.yaml
index ddd6804..487c3d7 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -35,6 +35,8 @@
squash: true
merge: true
rebase: false
+ autolink_jira:
+ - LIBCLOUD
protected_branches:
trunk:
required_status_checks:
@@ -46,6 +48,7 @@
- "Unit Tests (Python 3.8)"
- "Unit Tests (Python 3.9)"
- "Unit Tests (Python 3.10)"
+ - "Unit Tests (Python 3.11)"
- "Run Various Lint and Other Checks (3.8)"
- "Build and upload Documentation (3.8)"
- "Dependency Review"
diff --git a/.bandit.yaml b/.bandit.yaml
deleted file mode 100644
index 80ddbf0..0000000
--- a/.bandit.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-exclude_dirs:
- - .tox
- - .git
- - build
- - dist
- - venv
- - "tests/*"
-
-skips:
- - B411
diff --git a/.codecov.yml b/.codecov.yml
index 925a7a7..61caf6f 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -1,7 +1,3 @@
-codecov:
- #notify:
- #require_ci_to_pass: yes
-
coverage:
precision: 2 # decimal places to display: 0 <= value <= 4
round: nearest
diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index 61014db..0000000
--- a/.coveragerc
+++ /dev/null
@@ -1,32 +0,0 @@
-# .coveragerc to control coverage.py
-[run]
-branch = True
-source = libcloud
-
-[report]
-# Regexes for lines to exclude from consideration
-exclude_lines =
- # Have to re-enable the standard pragma
- pragma: no cover
-
- # Don't complain about missing debug-only code:
- def __repr__
- def __str__
- if self\.debug
-
- # Don't complain if tests don't hit defensive assertion code:
- raise AssertionError
- raise NotImplementedError
-
- # Don't complain if non-runnable code isn't run:
- if 0:
- if __name__ == .__main__.:
- __all__
- import
- deprecated_warning
- in_development_warning
-
-ignore_errors = True
-
-[html]
-directory = coverage_html_report
diff --git a/.github/actions/gh-action-pip-audit/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/actions/gh-action-pip-audit/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..f931fc5
--- /dev/null
+++ b/.github/actions/gh-action-pip-audit/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,64 @@
+name: Bug report
+description: Report a bug with pip-audit's GitHub Action
+labels: bug
+body:
+ - type: markdown
+ attributes:
+ value: >-
+ Thank you for reporting a potential bug in `gh-action-pip-audit`! Please
+ read the following carefully:
+
+
+ **IMPORTANT:** This issue tracker is for `pip-audit`'s
+ **GitHub Action**, the scaffolding that integrates `pip-audit` with your
+ CI. If the buggy behavior you are experiencing appears to be in
+ `pip-audit`, please file an issue
+ [against the `pip-audit` repo](https://github.com/pypa/pip-audit/issues/new/choose).
+
+
+ **IMPORTANT:** Please fill out every section below. Bug reports with
+ missing information will be given a lower priority or closed outright.
+
+
+ Before filing an issue, check out our
+ [troubleshooting guide](https://github.com/pypa/gh-action-pip-audit#troubleshooting) :)
+ - type: textarea
+ id: current-behavior
+ attributes:
+ label: Current behavior
+ description: >-
+ What issue are you having with the action? What were you trying to do
+ when the issue occurred?
+ placeholder: The action run succeeds when I ...
+ validations:
+ required: true
+ - type: textarea
+ id: expected-behavior
+ attributes:
+ label: Expected behavior
+ description: What should've happened instead?
+ placeholder: I expected the action run to fail.
+ validations:
+ required: true
+ - type: textarea
+ id: repro
+ attributes:
+ label: Steps to reproduce
+ description: What are the detailed steps we can follow to trigger this issue?
+ placeholder: |-
+ 1. ...
+ 2. ...
+ 3. ...
+ validations:
+ required: true
+ - type: textarea
+ id: context
+ attributes:
+ label: Relevant context
+ description: >-
+ Please include a link to an action run, as well as any logs that you think might
+ be helpful! You can
+ [follow these instructions](https://docs.github.com/en/actions/managing-workflow-runs/re-running-workflows-and-jobs#re-running-all-the-jobs-in-a-workflow)
+ to re-run the action with debug logging.
+ validations:
+ required: true
diff --git a/.github/actions/gh-action-pip-audit/.github/ISSUE_TEMPLATE/config.yml b/.github/actions/gh-action-pip-audit/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..ff27519
--- /dev/null
+++ b/.github/actions/gh-action-pip-audit/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,11 @@
+blank_issues_enabled: false
+contact_links:
+ - name: pip-audit's issue tracker
+ url: https://github.com/pypa/pip-audit/issues/new/choose
+ about: >-
+ You may want to file a report on pip-audit instead if your issue is not
+ directly related to this GitHub Action
+ - name: Troubleshooting guide
+ url: https://github.com/pypa/gh-action-pip-audit#troubleshooting
+ about: >-
+ Learn how to fix some common issues or enable debug logging here
diff --git a/.github/actions/gh-action-pip-audit/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/actions/gh-action-pip-audit/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000..c83f913
--- /dev/null
+++ b/.github/actions/gh-action-pip-audit/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,50 @@
+name: Feature request
+description: Suggest an idea for pip-audit's GitHub Action
+labels: enhancement
+body:
+ - type: markdown
+ attributes:
+ value: >-
+ Thank you for filing a feature request for `gh-action-pip-audit`! Please
+ read the following carefully:
+
+
+ **IMPORTANT:** This form is for `pip-audit`'s **GitHub Action**, the
+ scaffolding that integrates `pip-audit` with your CI. If you would like
+ a new feature in `pip-audit` itself, please go to
+ [the `pip-audit` repo](https://github.com/pypa/pip-audit/issues/new/choose).
+
+
+ **IMPORTANT:** Please fill out every required section below to the best
+ of your ability. Feature requests with missing information may be given
+ a lower priority or closed outright.
+ - type: textarea
+ id: problem
+ attributes:
+ label: Is your feature request related to a problem?
+ description: Describe how the current solution is deficient.
+ placeholder: I am frustrated when ...
+ validations:
+ required: true
+ - type: textarea
+ id: solution
+ attributes:
+ label: Describe the solution you'd like
+ description:
+ placeholder: I think gh-action-pip-audit would benefit from ...
+ validations:
+ required: true
+ - type: textarea
+ id: alternatives-considered
+ attributes:
+ label: Alternative solutions or features you've considered
+ description:
+ placeholder:
+ validations:
+ required: true
+ - type: textarea
+ id: context
+ attributes:
+ label: Additional context
+ description: Add any context or screenshots related to the feature request.
+ placeholder:
diff --git a/.github/actions/gh-action-pip-audit/.github/workflows/selftest.yml b/.github/actions/gh-action-pip-audit/.github/workflows/selftest.yml
index 8640284..261a198 100644
--- a/.github/actions/gh-action-pip-audit/.github/workflows/selftest.yml
+++ b/.github/actions/gh-action-pip-audit/.github/workflows/selftest.yml
@@ -88,3 +88,21 @@
PIP_AUDIT_OUTPUT: "${{ steps.pip-audit.outputs.internal-be-careful-output }}"
run: |
grep -E 'pyyaml\s+\|\s+5.1' <<< $(base64 -d <<< "${PIP_AUDIT_OUTPUT}")
+ selftest-pipaudit-fail:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: ./
+ id: pip-audit
+ with:
+ # we do not care about pip-audit's actual output in this test, we just need a file to pass
+ # in so as to not exercise `pip list` mode.
+ inputs: ./test/empty.txt
+ # pass in a fake flag here to reliably trigger the failure we're looking for.
+ internal-be-careful-extra-flags: --not-a-real-pip-audit-flag
+ internal-be-careful-allow-failure: true
+ - name: assert expected output
+ env:
+ PIP_AUDIT_OUTPUT: "${{ steps.pip-audit.outputs.internal-be-careful-output }}"
+ run: |
+ grep 'pip-audit did not return any output' <<< $(base64 -d <<< "${PIP_AUDIT_OUTPUT}")
diff --git a/.github/actions/gh-action-pip-audit/README.md b/.github/actions/gh-action-pip-audit/README.md
index c7f790d..ff434ac 100644
--- a/.github/actions/gh-action-pip-audit/README.md
+++ b/.github/actions/gh-action-pip-audit/README.md
@@ -32,7 +32,7 @@
- uses: actions/checkout@v3
- name: install
run: python -m pip install .
- - uses: pypa/gh-action-pip-audit@v1.0.5
+ - uses: pypa/gh-action-pip-audit@v1.0.8
```
Or, with a virtual environment:
@@ -48,7 +48,7 @@
python -m venv env/
source env/bin/activate
python -m pip install .
- - uses: pypa/gh-action-pip-audit@v1.0.5
+ - uses: pypa/gh-action-pip-audit@v1.0.8
with:
virtual-environment: env/
```
@@ -72,7 +72,7 @@
To audit one or more requirements-style inputs:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
inputs: requirements.txt dev-requirements.txt
```
@@ -80,7 +80,7 @@
To audit a project that uses `pyproject.toml` for its dependencies:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
# NOTE: this can be `.`, for the current directory
inputs: path/to/project/
@@ -108,7 +108,7 @@
current directory:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
virtual-environment: env/
# Note the absence of `input:`, since we're auditing the environment.
@@ -128,7 +128,7 @@
Example:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
local: true
```
@@ -145,7 +145,7 @@
To audit with OSV instead of PyPI:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
vulnerability-service: osv
```
@@ -160,7 +160,7 @@
Example:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
# NOTE: only works with requirements-style inputs
inputs: requirements.txt
@@ -177,7 +177,7 @@
Example:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
# NOTE: only works with requirements-style inputs
inputs: requirements.txt
@@ -195,7 +195,7 @@
Example:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
summary: false
```
@@ -214,7 +214,7 @@
Example:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
index-url: https://example.corporate.local/simple
```
@@ -229,7 +229,7 @@
Example:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
extra-index-urls: |
https://example.corporate.local/simple
@@ -246,7 +246,7 @@
Example
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
ignore-vulns: |
GHSA-XXXX-YYYYYY
@@ -276,29 +276,24 @@
Example:
```yaml
- - uses: pypa/gh-action-pip-audit@v1.0.5
+ - uses: pypa/gh-action-pip-audit@v1.0.8
with:
internal-be-careful-allow-failure: true
```
- #### `internal-be-careful-debug`
+#### `internal-be-careful-extra-flags`
+**Default**: `""`
- **Default**: `false`
+The `internal-be-careful-extra-flags` setting passes the specified flags
+to `pip-audit`.
- The `internal-be-careful-debug` setting enables additional debug logs,
- both within `pip-audit` itself and the action's harness code. You can
- use it to debug troublesome configurations.
+Example:
- Be mindful that `pip-audit`'s own debug logs contain HTTP requests,
- which may or may not be sensitive in your use case.
-
- Example:
-
- ```yaml
- - uses: pypa/gh-action-pip-audit@v1.0.5
- with:
- internal-be-careful-debug: true
- ```
+```yaml
+- uses: pypa/gh-action-pip-audit@v1.0.8
+ with:
+ internal-be-careful-extra-flags: --not-a-real-pip-audit-flag
+```
</details>
@@ -312,7 +307,7 @@
`require-hashes: true`:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
inputs: requirements.txt
require-hashes: true
@@ -321,7 +316,7 @@
or:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
inputs: requirements.txt
no-deps: true
@@ -342,7 +337,7 @@
To minimize external dependencies, you can opt into a virtual environment:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
# must be populated earlier in the CI
virtual-environment: env/
@@ -352,13 +347,19 @@
in the virtual environment should be included:
```yaml
-- uses: pypa/gh-action-pip-audit@v1.0.5
+- uses: pypa/gh-action-pip-audit@v1.0.8
with:
# must be populated earlier in the CI
virtual-environment: env/
local: true
```
+### There's an issue with the action and I want to enable debug logging!
+
+The action prints debug information when the `ACTIONS_STEP_DEBUG` secret is set
+to `true``. You should be able to enable this behavior by
+[following these instructions](https://docs.github.com/en/actions/managing-workflow-runs/re-running-workflows-and-jobs#re-running-all-the-jobs-in-a-workflow).
+
## Tips and Tricks
### Running against a pipenv project
@@ -382,7 +383,7 @@
run: |
pipx run pipfile-requirements Pipfile.lock > requirements.txt
- - uses: pypa/gh-action-pip-audit@v1.0.5
+ - uses: pypa/gh-action-pip-audit@v1.0.8
with:
inputs: requirements.txt
```
diff --git a/.github/actions/gh-action-pip-audit/action.py b/.github/actions/gh-action-pip-audit/action.py
index 75d8d7f..dd624ad 100755
--- a/.github/actions/gh-action-pip-audit/action.py
+++ b/.github/actions/gh-action-pip-audit/action.py
@@ -18,7 +18,7 @@
_GITHUB_STEP_SUMMARY = Path(os.getenv("GITHUB_STEP_SUMMARY")).open("a")
_GITHUB_OUTPUT = Path(os.getenv("GITHUB_OUTPUT")).open("a")
_RENDER_SUMMARY = os.getenv("GHA_PIP_AUDIT_SUMMARY", "true") == "true"
-_DEBUG = os.getenv("GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_DEBUG", "false") != "false"
+_DEBUG = os.getenv("RUNNER_DEBUG") is not None
def _template(name):
@@ -33,7 +33,7 @@
def _debug(msg):
if _DEBUG:
- print(f"\033[93mDEBUG: {msg}\033[0m", file=sys.stderr)
+ print(f"::debug::{msg}")
def _log(msg):
@@ -64,7 +64,7 @@
"--desc",
# Write the output to this logfile, which we'll turn into the step summary (if configured).
"--output=/tmp/pip-audit-output.txt",
-]
+] + os.getenv("GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_EXTRA_FLAGS").split()
if _DEBUG:
pip_audit_args.append("--verbose")
@@ -135,15 +135,19 @@
else:
_summary("❌ pip-audit found one or more problems")
- with open("/tmp/pip-audit-output.txt", "r") as io:
- output = io.read()
+ output = "⚠️ pip-audit did not return any output"
+ try:
+ with open("/tmp/pip-audit-output.txt", "r") as io:
+ output = io.read()
+ except OSError as ex:
+ _log(ex)
- # This is really nasty: our output contains multiple lines,
- # so we can't naively stuff it into an output.
- print(f"output={b64encode(output.encode()).decode()}", file=_GITHUB_OUTPUT)
+ # This is really nasty: our output contains multiple lines,
+ # so we can't naively stuff it into an output.
+ print(f"output={b64encode(output.encode()).decode()}", file=_GITHUB_OUTPUT)
- _log(output)
- _summary(output)
+ _log(output)
+ _summary(output)
_log(status.stdout)
diff --git a/.github/actions/gh-action-pip-audit/action.yml b/.github/actions/gh-action-pip-audit/action.yml
index 3574e61..39e9d3d 100644
--- a/.github/actions/gh-action-pip-audit/action.yml
+++ b/.github/actions/gh-action-pip-audit/action.yml
@@ -46,10 +46,10 @@
description: "don't fail the job if the audit fails (default false)"
required: false
default: false
- internal-be-careful-debug:
- description: "run with debug logs (default false)"
+ internal-be-careful-extra-flags:
+ description: "extra flags to be passed in to pip-audit"
required: false
- default: false
+ default: ""
outputs:
internal-be-careful-output:
description: "the column-formatted output from pip-audit, wrapped as base64"
@@ -83,5 +83,5 @@
GHA_PIP_AUDIT_EXTRA_INDEX_URLS: "${{ inputs.extra-index-urls }}"
GHA_PIP_AUDIT_IGNORE_VULNS: "${{ inputs.ignore-vulns }}"
GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_ALLOW_FAILURE: "${{ inputs.internal-be-careful-allow-failure }}"
- GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_DEBUG: "${{ inputs.internal-be-careful-debug }}"
+ GHA_PIP_AUDIT_INTERNAL_BE_CAREFUL_EXTRA_FLAGS: "${{ inputs.internal-be-careful-extra-flags }}"
shell: bash
diff --git a/.github/actions/gh-action-pip-audit/requirements.txt b/.github/actions/gh-action-pip-audit/requirements.txt
index 931128f..546e8fe 100644
--- a/.github/actions/gh-action-pip-audit/requirements.txt
+++ b/.github/actions/gh-action-pip-audit/requirements.txt
@@ -1 +1 @@
-pip-audit ~= 2.0, >= 2.4.13
+pip-audit ~= 2.0, >= 2.5.6
diff --git a/.gitmodules b/.github/actions/gh-action-pip-audit/test/empty.txt
similarity index 100%
rename from .gitmodules
rename to .github/actions/gh-action-pip-audit/test/empty.txt
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 4941da4..7868071 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -3,9 +3,11 @@
- package-ecosystem: "github-actions"
directory: "/"
schedule:
- interval: "daily"
+ interval: "weekly"
+ open-pull-requests-limit: 2
- package-ecosystem: "pip"
directory: "/"
schedule:
- interval: "daily"
+ interval: "weekly"
+ open-pull-requests-limit: 2
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index 1183e7b..9f61f1b 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -16,6 +16,11 @@
actions: write # Needed for skip-duplicate-jobs job
contents: read
+env:
+ # Needed if we want colors in pytest output without tty and script -e -c wrapper
+ PY_COLORS: "1"
+ FORCE_COLOR: "1"
+
jobs:
# Special job which skips duplicate jobs
pre_job:
@@ -80,7 +85,7 @@
- name: Run tox target
run: |
- script -e -c "tox -e integration-storage"
+ tox -e integration-storage
env:
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 9d881eb..cf03c62 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -14,6 +14,11 @@
actions: write # Needed for skip-duplicate-jobs job
contents: read
+env:
+ # Needed if we want colors in pytest output without tty and script -e -c wrapper
+ PY_COLORS: "1"
+ FORCE_COLOR: "1"
+
jobs:
# Special job which skips duplicate jobs
pre_job:
@@ -54,7 +59,9 @@
- 3.9
- "3.10"
- "3.11"
- - "pypy-3.7"
+ - "3.12-dev"
+ # TODO: Investigate why it started failing with cryptic error on CI
+ #- "pypy-3.7"
os:
- ubuntu-latest
include:
@@ -95,7 +102,7 @@
- name: Setup Dotnet 6
if: ${{ matrix.python_version == 'pyjion' }}
- uses: actions/setup-dotnet@v3.0.3
+ uses: actions/setup-dotnet@v3.2.0
with:
dotnet-version: "6.0.100"
@@ -118,12 +125,12 @@
- name: Run unit tests tox target
run: |
- script -e -c "tox -e py${{ matrix.python_version }}"
+ tox -e py${{ matrix.python_version }}
- name: Run dist install checks tox target
if: ${{ matrix.python_version != 'pypy-3.7' && matrix.python_version != 'pyjion' }}
run: |
- script -e -c "tox -e py${{ matrix.python_version }}-dist,py${{ matrix.python_version }}-dist-wheel"
+ tox -e py${{ matrix.python_version }}-dist,py${{ matrix.python_version }}-dist-wheel
code_coverage:
name: Generate Code Coverage
@@ -165,7 +172,13 @@
- name: Run Checks
run: |
- script -e -c "tox -e coverage-ci"
+ tox -e coverage-ci
+
+ - name: Upload Coverage to codecov.io
+ uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
+ with:
+ fail_ci_if_error: true
+ verbose: true
lint_checks:
name: Run Various Lint and Other Checks
@@ -207,7 +220,7 @@
- name: Run Checks
run: |
- script -e -c "tox -e black-check,isort-check,pyupgrade,checks,import-timings,lint,pylint"
+ tox -e black-check,isort-check,pyupgrade,checks,import-timings,lint,pylint
build_test_docker_image:
name: Build and Verify Docker Image
@@ -287,6 +300,7 @@
# setuptools which we don't install or depend on directly
ignore-vulns: |
GHSA-r9hx-vwmv-q579
+ PYSEC-2022-43012
- name: Cleanup
run: |
@@ -302,7 +316,7 @@
- name: Run Bandit Check
run: |
- script -e -c "tox -e bandit"
+ tox -e bandit
micro-benchmarks:
name: Micro Benchmarks
@@ -344,7 +358,7 @@
- name: Run Micro Benchmarks
run: |
- script -e -c "tox -e micro-benchmarks"
+ tox -e micro-benchmarks
docs:
name: Build and upload Documentation
@@ -391,7 +405,7 @@
- name: Build Docs
run: |
- script -e -c "tox -e docs-ci"
+ tox -e docs-ci
- name: Trigger ReadTheDocs build
env:
diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index a0b4ddd..0000000
--- a/.pylintrc
+++ /dev/null
@@ -1,39 +0,0 @@
-[MASTER]
-# Add <file or directory> to the black list. It should be a base name, not a
-# path. You may set this option multiple times.
-ignore=test,constants
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-
-[MESSAGES CONTROL]
-disable=redefined-builtin,too-many-arguments,too-few-public-methods,missing-docstring,invalid-name,abstract-method
-
-
-[TYPECHECK]
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E0201 when accessed. Python regular
-# expressions are accepted.
-generated-members=async_request,objects
-
-[VARIABLES]
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# A regular expression matching names used for dummy variables (i.e. not used).
-dummy-variables-rgx=_|dummy
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-[FORMAT]
-max-line-length=100
-max-module-lines=1000
-indent-string=' '
diff --git a/.ratignore b/.ratignore
index 9668cf0..346a627 100644
--- a/.ratignore
+++ b/.ratignore
@@ -1,19 +1,10 @@
-RELEASING
-MANIFEST
MANIFEST.in
.gitignore
tox.ini
-apidocs/
-CHANGES
-HACKING
-test/storage/fixtures/
-test/compute/fixtures/
-test/loadbalancer/fixtures/
-test/dns/fixtures/
-test/container/fixtures/
-coverage_html_report/
-.coverage
-.coveragerc
+docs/apidocs.rst
+CHANGES.rst
+.codecov.rc
+pyproject.toml
libcloud/data/pricing.json
libcloud/common/__init__.py
libcloud/compute/__init__.py
@@ -21,5 +12,10 @@
libcloud/storage/__init__.py
libcloud/loadbalancer/__init__.py
libcloud/dns/__init__.py
-test/storage/__init__.py
-test/pricing_test.json
+libcloud/test/storage/fixtures/
+libcloud/test/compute/fixtures/
+libcloud/test/loadbalancer/fixtures/
+libcloud/test/dns/fixtures/
+libcloud/test/container/fixtures/
+libcloud/test/storage/__init__.py
+libcloud/test/pricing_test.json
diff --git a/CHANGES.rst b/CHANGES.rst
index cce0e66..0409547 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -7,13 +7,22 @@
Compute
~~~~~~~
-Remove obsolete compute driver where the provider is either dead or not
-offering those services anymore: Bluebox, bsnlcloud, Cloudwatt, Enomaly,
-ElasticHosts, ElasticStack, GoGrid, Gridspot, HostVirtual, Joyent, Med-1,
-Nephoscale, 1on1, ProfitBricks, ServerLove, SkaliCloud, Softlayer, Voxel.
+- Remove obsolete compute driver where the provider is either dead or not
+ offering those services anymore: Bluebox, bsnlcloud, Cloudwatt, Enomaly,
+ ElasticHosts, ElasticStack, GoGrid, Gridspot, HostVirtual, Joyent, Med-1,
+ Nephoscale, 1on1, ProfitBricks, ServerLove, SkaliCloud, Softlayer, Voxel.
-(GITHUB-1743, GITHUB-1852)
-[Anthony Monthe - @ZuluPro, Tomaz Muraus - @Kami]
+ (GITHUB-1743, GITHUB-1852)
+ [Anthony Monthe - @ZuluPro, Tomaz Muraus - @Kami]
+
+- [Outscale] Fix ``list_nodes()`` and ``list_volumes()`` method.
+ (GITHUB-1877)
+ [Matthias Gatto - @outscale-mgo]
+
+- [Azure ARM] Implement pagination in the ``list_nodes()`` method. This fixes a
+ bug which would result in sometimes not all nodes being returned.
+ (GITHUB-1824, GITHUB-1850)
+ [Jan Müller - @ojan-mue]
Storage
~~~~~~~
@@ -32,6 +41,34 @@
(GITHUB-1796)
[@shengwubin]
+- [S3] Support all available storage classes. Previously only "standard" and
+ "reduced_redundancy" were supported.
+ (GITHUB-1875)
+ [Mohammad Aburadeh - @mohammad-aburadeh]
+
+- [CloudFiles] Fix ``get_endpoint_url()`` throwing an exception when being used
+ with ``use_internal_url=True`` argument.
+ (GITHUB-1883, GITHUB-1884)
+ [Marcus T - @llamasoft]
+
+- [CloudFiles] Update OpenStack connection handling code to only re-connect in
+ case connection details (scheme, host, port) have changed.
+
+ This should result in significant performance improvements when downloading
+ objects since the underlying HTTP connection will be properly re-used.
+ (GITHUB-1885, GITHUB-1886)
+ [Marcus T - @llamasoft]
+
+Other
+~~~~~
+
+- Move Python tooling (pytest, bandit, pylint, mypy, coverage) config options
+ from separate config files into single pyproject.yaml config files.
+
+ NOTE: This change only affects development process and nothing else.
+ (GITHUB-1901)
+ [RS Nikhil Krishna - @rsnk96]
+
Changes in Apache Libcloud 3.7.0
--------------------------------
diff --git a/MANIFEST.in b/MANIFEST.in
index cc4af03..a8ddee3 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,7 +4,7 @@
include CHANGES.rst
include README.rst
include tox.ini
-include .pylintrc
+include pyproject.toml
include requirements-tests.txt
include requirements-lint.txt
include libcloud/data/pricing.json
diff --git a/contrib/generate_contributor_list.py b/contrib/generate_contributor_list.py
index 520fe30..201c226 100755
--- a/contrib/generate_contributor_list.py
+++ b/contrib/generate_contributor_list.py
@@ -106,7 +106,6 @@
def convert_to_markdown(contributors_map, include_tickets=False):
-
# Contributors are sorted in ascending lexiographical order based on their
# last name
def compare(item1, item2):
diff --git a/contrib/scrape-azure-prices.py b/contrib/scrape-azure-prices.py
index 53ee06b..7c33ef5 100755
--- a/contrib/scrape-azure-prices.py
+++ b/contrib/scrape-azure-prices.py
@@ -40,7 +40,6 @@
result = {"windows": {}, "linux": {}}
parsed_sizes = {"lowpriority", "basic", "standard"}
for offer, value in prices_raw["offers"].items():
-
size_raw = offer.split("-")
# Servers that go by the core with global price are not yet added
if len(size_raw) != 3 or size_raw[2] not in parsed_sizes:
diff --git a/contrib/scrape-ec2-prices.py b/contrib/scrape-ec2-prices.py
index 6a029ea..a4b6f5a 100755
--- a/contrib/scrape-ec2-prices.py
+++ b/contrib/scrape-ec2-prices.py
@@ -305,7 +305,7 @@
"""
result = []
- for (numeric, alpha, other) in RE_NUMERIC_OTHER.findall(key_value[0]):
+ for numeric, alpha, other in RE_NUMERIC_OTHER.findall(key_value[0]):
numeric = int(numeric) if numeric else -1
alpha = INSTANCE_SIZES.index(alpha) if alpha in INSTANCE_SIZES else alpha
alpha = str(alpha)
diff --git a/docs/compute/_supported_methods_block_storage.rst b/docs/compute/_supported_methods_block_storage.rst
index 6621e47..c8ae023 100644
--- a/docs/compute/_supported_methods_block_storage.rst
+++ b/docs/compute/_supported_methods_block_storage.rst
@@ -1,57 +1,57 @@
.. NOTE: This file has been generated automatically using generate_provider_feature_matrix_table.py script, don't manually edit it
-===================================== ============ ============= ============== ============= ============= ============== ===============
-Provider list volumes create volume destroy volume attach volume detach volume list snapshots create snapshot
-===================================== ============ ============= ============== ============= ============= ============== ===============
-`Abiquo`_ no no no no no no no
-`Aliyun ECS`_ yes yes yes yes yes yes yes
-`PCextreme AuroraCompute`_ yes yes yes yes yes no yes
-`Azure Virtual machines`_ yes yes yes yes yes no yes
-`Azure Virtual machines`_ yes yes yes yes yes yes yes
-`Brightbox`_ no no no no no no no
-`Cloudscale`_ no no no no no no no
-`CloudSigma (API v2.0)`_ yes yes yes yes yes no no
-`CloudStack`_ yes yes yes yes yes no yes
-`DigitalOcean`_ yes yes yes yes yes yes yes
-`DimensionData`_ no no no no no no no
-`Amazon EC2`_ yes yes yes yes yes yes yes
-`EquinixMetal`_ yes yes yes yes yes yes yes
-`Eucalyptus`_ yes yes yes yes yes yes yes
-`Exoscale`_ yes yes yes yes yes no yes
-`Gandi`_ yes yes yes yes yes no no
-`Google Compute Engine`_ yes yes yes yes yes yes yes
-`GiG G8 Node Provider`_ yes yes yes yes yes no no
-`Gridscale`_ yes yes yes yes yes yes yes
-`Ikoula`_ yes yes yes yes yes no yes
-`InternetSolutions`_ no no no no no no no
-`Kamatera`_ no no no no no no no
-`KTUCloud`_ yes yes yes yes yes no yes
-`kubevirt`_ yes yes yes yes yes no no
-`Libvirt`_ no no no no no no no
-`Linode`_ yes yes yes yes yes no no
-`Maxihost`_ no no no no no no no
-`Nimbus`_ yes yes yes yes yes yes yes
-`NTTAmerica`_ no no no no no no no
-`NTTC-CIS`_ no no no no no no no
-`OnApp`_ no no no no no no no
-`OpenNebula (v3.8)`_ yes yes yes yes yes no no
-`OpenStack`_ yes yes yes yes yes no no
-`Outscale API`_ yes yes yes yes yes yes yes
-`Outscale INC`_ yes yes yes yes yes yes yes
-`Outscale SAS`_ yes yes yes yes yes yes yes
-`Ovh`_ yes yes yes yes yes yes yes
-`Rackspace Cloud (Next Gen)`_ yes yes yes yes yes yes yes
-`Rackspace Cloud (First Gen)`_ yes yes yes yes yes no no
-`RimuHosting`_ no no no no no no no
-`Scaleway`_ yes yes yes no no yes yes
-`vCloud`_ no no no no no no no
-`Upcloud`_ no no no no no no no
-`VCL`_ no no no no no no no
-`vCloud`_ no no no no no no no
-`vps.net`_ no no no no no no no
-`VMware vSphere`_ no no no no no no no
-`Vultr`_ yes yes yes yes yes no no
-===================================== ============ ============= ============== ============= ============= ============== ===============
+============================== ============ ============= ============== ============= ============= ============== ===============
+Provider list volumes create volume destroy volume attach volume detach volume list snapshots create snapshot
+============================== ============ ============= ============== ============= ============= ============== ===============
+`Abiquo`_ no no no no no no no
+`Aliyun ECS`_ yes yes yes yes yes yes yes
+`PCextreme AuroraCompute`_ yes yes yes yes yes no yes
+`Azure Virtual machines`_ yes yes yes yes yes no yes
+`Azure Virtual machines`_ yes yes yes yes yes yes yes
+`Brightbox`_ no no no no no no no
+`Cloudscale`_ no no no no no no no
+`CloudSigma (API v2.0)`_ yes yes yes yes yes no no
+`CloudStack`_ yes yes yes yes yes no yes
+`DigitalOcean`_ yes yes yes yes yes yes yes
+`DimensionData`_ no no no no no no no
+`Amazon EC2`_ yes yes yes yes yes yes yes
+`EquinixMetal`_ yes yes yes yes yes yes yes
+`Eucalyptus`_ yes yes yes yes yes yes yes
+`Exoscale`_ yes yes yes yes yes no yes
+`Gandi`_ yes yes yes yes yes no no
+`Google Compute Engine`_ yes yes yes yes yes yes yes
+`GiG G8 Node Provider`_ yes yes yes yes yes no no
+`Gridscale`_ yes yes yes yes yes yes yes
+`Ikoula`_ yes yes yes yes yes no yes
+`InternetSolutions`_ no no no no no no no
+`Kamatera`_ no no no no no no no
+`KTUCloud`_ yes yes yes yes yes no yes
+`kubevirt`_ yes yes yes yes yes no no
+`Libvirt`_ no no no no no no no
+`Linode`_ yes yes yes yes yes no no
+`Maxihost`_ no no no no no no no
+`Nimbus`_ yes yes yes yes yes yes yes
+`NTTAmerica`_ no no no no no no no
+`NTTC-CIS`_ no no no no no no no
+`OnApp`_ no no no no no no no
+`OpenNebula (v3.8)`_ yes yes yes yes yes no no
+`OpenStack`_ yes yes yes yes yes no no
+`Outscale API`_ yes yes yes yes yes yes yes
+`Outscale INC`_ yes yes yes yes yes yes yes
+`Outscale SAS`_ yes yes yes yes yes yes yes
+`Ovh`_ yes yes yes yes yes yes yes
+`Rackspace Cloud (Next Gen)`_ yes yes yes yes yes yes yes
+`Rackspace Cloud (First Gen)`_ yes yes yes yes yes no no
+`RimuHosting`_ no no no no no no no
+`Scaleway`_ yes yes yes no no yes yes
+`vCloud`_ no no no no no no no
+`Upcloud`_ no no no no no no no
+`VCL`_ no no no no no no no
+`vCloud`_ no no no no no no no
+`vps.net`_ no no no no no no no
+`VMware vSphere`_ no no no no no no no
+`Vultr`_ yes yes yes yes yes no no
+============================== ============ ============= ============== ============= ============= ============== ===============
.. _`Abiquo`: http://www.abiquo.com/
.. _`Aliyun ECS`: https://www.aliyun.com/product/ecs
diff --git a/docs/compute/_supported_methods_image_management.rst b/docs/compute/_supported_methods_image_management.rst
index f40cdf4..c121c6b 100644
--- a/docs/compute/_supported_methods_image_management.rst
+++ b/docs/compute/_supported_methods_image_management.rst
@@ -1,57 +1,57 @@
.. NOTE: This file has been generated automatically using generate_provider_feature_matrix_table.py script, don't manually edit it
-===================================== =========== ========= ============ ============ ==========
-Provider list images get image create image delete image copy image
-===================================== =========== ========= ============ ============ ==========
-`Abiquo`_ yes no no no no
-`Aliyun ECS`_ yes yes yes yes yes
-`PCextreme AuroraCompute`_ yes no no no no
-`Azure Virtual machines`_ yes no no no no
-`Azure Virtual machines`_ yes yes no no no
-`Brightbox`_ yes no no no no
-`Cloudscale`_ yes no no no no
-`CloudSigma (API v2.0)`_ yes no no no no
-`CloudStack`_ yes no no no no
-`DigitalOcean`_ yes yes yes yes no
-`DimensionData`_ yes no no no no
-`Amazon EC2`_ yes yes yes yes yes
-`EquinixMetal`_ yes no no no no
-`Eucalyptus`_ yes yes yes yes yes
-`Exoscale`_ yes no no no no
-`Gandi`_ yes no no no no
-`Google Compute Engine`_ yes no no no no
-`GiG G8 Node Provider`_ yes no no no no
-`Gridscale`_ yes yes yes yes no
-`Ikoula`_ yes no no no no
-`InternetSolutions`_ yes no no no no
-`Kamatera`_ yes no no no no
-`KTUCloud`_ yes no no no no
-`kubevirt`_ yes no no no no
-`Libvirt`_ no no no no no
-`Linode`_ yes no yes yes no
-`Maxihost`_ yes no no no no
-`Nimbus`_ yes yes yes yes yes
-`NTTAmerica`_ yes no no no no
-`NTTC-CIS`_ yes no no no no
-`OnApp`_ yes no no no no
-`OpenNebula (v3.8)`_ yes no no no no
-`OpenStack`_ yes yes no no no
-`Outscale API`_ yes yes yes yes no
-`Outscale INC`_ yes yes yes yes yes
-`Outscale SAS`_ yes yes yes yes yes
-`Ovh`_ yes yes no no no
-`Rackspace Cloud (Next Gen)`_ yes yes yes yes no
-`Rackspace Cloud (First Gen)`_ yes yes yes yes no
-`RimuHosting`_ yes no no no no
-`Scaleway`_ yes yes yes yes no
-`vCloud`_ yes no no no no
-`Upcloud`_ yes no no no no
-`VCL`_ yes no no no no
-`vCloud`_ yes no no no no
-`vps.net`_ yes no no no no
-`VMware vSphere`_ yes no no no no
-`Vultr`_ yes no no no no
-===================================== =========== ========= ============ ============ ==========
+============================== =========== ========= ============ ============ ==========
+Provider list images get image create image delete image copy image
+============================== =========== ========= ============ ============ ==========
+`Abiquo`_ yes no no no no
+`Aliyun ECS`_ yes yes yes yes yes
+`PCextreme AuroraCompute`_ yes no no no no
+`Azure Virtual machines`_ yes no no no no
+`Azure Virtual machines`_ yes yes no no no
+`Brightbox`_ yes no no no no
+`Cloudscale`_ yes no no no no
+`CloudSigma (API v2.0)`_ yes no no no no
+`CloudStack`_ yes no no no no
+`DigitalOcean`_ yes yes yes yes no
+`DimensionData`_ yes no no no no
+`Amazon EC2`_ yes yes yes yes yes
+`EquinixMetal`_ yes no no no no
+`Eucalyptus`_ yes yes yes yes yes
+`Exoscale`_ yes no no no no
+`Gandi`_ yes no no no no
+`Google Compute Engine`_ yes no no no no
+`GiG G8 Node Provider`_ yes no no no no
+`Gridscale`_ yes yes yes yes no
+`Ikoula`_ yes no no no no
+`InternetSolutions`_ yes no no no no
+`Kamatera`_ yes no no no no
+`KTUCloud`_ yes no no no no
+`kubevirt`_ yes no no no no
+`Libvirt`_ no no no no no
+`Linode`_ yes no yes yes no
+`Maxihost`_ yes no no no no
+`Nimbus`_ yes yes yes yes yes
+`NTTAmerica`_ yes no no no no
+`NTTC-CIS`_ yes no no no no
+`OnApp`_ yes no no no no
+`OpenNebula (v3.8)`_ yes no no no no
+`OpenStack`_ yes yes no no no
+`Outscale API`_ yes yes yes yes no
+`Outscale INC`_ yes yes yes yes yes
+`Outscale SAS`_ yes yes yes yes yes
+`Ovh`_ yes yes no no no
+`Rackspace Cloud (Next Gen)`_ yes yes yes yes no
+`Rackspace Cloud (First Gen)`_ yes yes yes yes no
+`RimuHosting`_ yes no no no no
+`Scaleway`_ yes yes yes yes no
+`vCloud`_ yes no no no no
+`Upcloud`_ yes no no no no
+`VCL`_ yes no no no no
+`vCloud`_ yes no no no no
+`vps.net`_ yes no no no no
+`VMware vSphere`_ yes no no no no
+`Vultr`_ yes no no no no
+============================== =========== ========= ============ ============ ==========
.. _`Abiquo`: http://www.abiquo.com/
.. _`Aliyun ECS`: https://www.aliyun.com/product/ecs
diff --git a/docs/compute/_supported_methods_key_pair_management.rst b/docs/compute/_supported_methods_key_pair_management.rst
index e663a2e..ef255a2 100644
--- a/docs/compute/_supported_methods_key_pair_management.rst
+++ b/docs/compute/_supported_methods_key_pair_management.rst
@@ -1,57 +1,57 @@
.. NOTE: This file has been generated automatically using generate_provider_feature_matrix_table.py script, don't manually edit it
-===================================== ============== ============ =============== ============================= =========================== ===============
-Provider list key pairs get key pair create key pair import public key from string import public key from file delete key pair
-===================================== ============== ============ =============== ============================= =========================== ===============
-`Abiquo`_ no no no no no no
-`Aliyun ECS`_ no no no no no no
-`PCextreme AuroraCompute`_ yes yes yes yes no yes
-`Azure Virtual machines`_ no no no no no no
-`Azure Virtual machines`_ no no no no no no
-`Brightbox`_ no no no no no no
-`Cloudscale`_ no no no no no no
-`CloudSigma (API v2.0)`_ yes yes yes yes no yes
-`CloudStack`_ yes yes yes yes no yes
-`DigitalOcean`_ yes yes yes no no yes
-`DimensionData`_ no no no no no no
-`Amazon EC2`_ yes yes yes yes no yes
-`EquinixMetal`_ yes no yes no no yes
-`Eucalyptus`_ yes yes yes yes no yes
-`Exoscale`_ yes yes yes yes no yes
-`Gandi`_ yes yes no yes no yes
-`Google Compute Engine`_ no no no no no no
-`GiG G8 Node Provider`_ no no no no no no
-`Gridscale`_ yes no no yes no no
-`Ikoula`_ yes yes yes yes no yes
-`InternetSolutions`_ no no no no no no
-`Kamatera`_ no no no no no no
-`KTUCloud`_ yes yes yes yes no yes
-`kubevirt`_ no no no no no no
-`Libvirt`_ no no no no no no
-`Linode`_ no no no no no no
-`Maxihost`_ yes no yes no no no
-`Nimbus`_ yes yes yes yes no yes
-`NTTAmerica`_ no no no no no no
-`NTTC-CIS`_ no no no no no no
-`OnApp`_ yes yes no yes no yes
-`OpenNebula (v3.8)`_ no no no no no no
-`OpenStack`_ no no no no no no
-`Outscale API`_ yes yes yes no no yes
-`Outscale INC`_ yes yes yes yes no yes
-`Outscale SAS`_ yes yes yes yes no yes
-`Ovh`_ yes yes no yes no yes
-`Rackspace Cloud (Next Gen)`_ yes yes yes yes no yes
-`Rackspace Cloud (First Gen)`_ no no no no no no
-`RimuHosting`_ no no no no no no
-`Scaleway`_ yes no no yes no yes
-`vCloud`_ no no no no no no
-`Upcloud`_ no no no no no no
-`VCL`_ no no no no no no
-`vCloud`_ no no no no no no
-`vps.net`_ no no no no no no
-`VMware vSphere`_ no no no no no no
-`Vultr`_ yes yes no yes no yes
-===================================== ============== ============ =============== ============================= =========================== ===============
+============================== ============== ============ =============== ============================= =========================== ===============
+Provider list key pairs get key pair create key pair import public key from string import public key from file delete key pair
+============================== ============== ============ =============== ============================= =========================== ===============
+`Abiquo`_ no no no no no no
+`Aliyun ECS`_ no no no no no no
+`PCextreme AuroraCompute`_ yes yes yes yes no yes
+`Azure Virtual machines`_ no no no no no no
+`Azure Virtual machines`_ no no no no no no
+`Brightbox`_ no no no no no no
+`Cloudscale`_ no no no no no no
+`CloudSigma (API v2.0)`_ yes yes yes yes no yes
+`CloudStack`_ yes yes yes yes no yes
+`DigitalOcean`_ yes yes yes no no yes
+`DimensionData`_ no no no no no no
+`Amazon EC2`_ yes yes yes yes no yes
+`EquinixMetal`_ yes no yes no no yes
+`Eucalyptus`_ yes yes yes yes no yes
+`Exoscale`_ yes yes yes yes no yes
+`Gandi`_ yes yes no yes no yes
+`Google Compute Engine`_ no no no no no no
+`GiG G8 Node Provider`_ no no no no no no
+`Gridscale`_ yes no no yes no no
+`Ikoula`_ yes yes yes yes no yes
+`InternetSolutions`_ no no no no no no
+`Kamatera`_ no no no no no no
+`KTUCloud`_ yes yes yes yes no yes
+`kubevirt`_ no no no no no no
+`Libvirt`_ no no no no no no
+`Linode`_ no no no no no no
+`Maxihost`_ yes no yes no no no
+`Nimbus`_ yes yes yes yes no yes
+`NTTAmerica`_ no no no no no no
+`NTTC-CIS`_ no no no no no no
+`OnApp`_ yes yes no yes no yes
+`OpenNebula (v3.8)`_ no no no no no no
+`OpenStack`_ no no no no no no
+`Outscale API`_ yes yes yes no no yes
+`Outscale INC`_ yes yes yes yes no yes
+`Outscale SAS`_ yes yes yes yes no yes
+`Ovh`_ yes yes no yes no yes
+`Rackspace Cloud (Next Gen)`_ yes yes yes yes no yes
+`Rackspace Cloud (First Gen)`_ no no no no no no
+`RimuHosting`_ no no no no no no
+`Scaleway`_ yes no no yes no yes
+`vCloud`_ no no no no no no
+`Upcloud`_ no no no no no no
+`VCL`_ no no no no no no
+`vCloud`_ no no no no no no
+`vps.net`_ no no no no no no
+`VMware vSphere`_ no no no no no no
+`Vultr`_ yes yes no yes no yes
+============================== ============== ============ =============== ============================= =========================== ===============
.. _`Abiquo`: http://www.abiquo.com/
.. _`Aliyun ECS`: https://www.aliyun.com/product/ecs
diff --git a/docs/compute/_supported_methods_main.rst b/docs/compute/_supported_methods_main.rst
index 3a84bf4..4ed5f39 100644
--- a/docs/compute/_supported_methods_main.rst
+++ b/docs/compute/_supported_methods_main.rst
@@ -1,57 +1,57 @@
.. NOTE: This file has been generated automatically using generate_provider_feature_matrix_table.py script, don't manually edit it
-===================================== ========== =========== =========== ============ ========== ========= =========== ========== ===========
-Provider list nodes create node reboot node destroy node start node stop node list images list sizes deploy node
-===================================== ========== =========== =========== ============ ========== ========= =========== ========== ===========
-`Abiquo`_ yes yes yes yes no no yes yes no
-`Aliyun ECS`_ yes yes yes yes yes yes yes yes yes
-`PCextreme AuroraCompute`_ yes yes yes yes no no yes yes yes
-`Azure Virtual machines`_ yes yes yes yes no no yes yes yes
-`Azure Virtual machines`_ yes yes yes yes yes yes yes yes yes
-`Brightbox`_ yes yes no yes no no yes yes no
-`Cloudscale`_ yes yes yes yes yes yes yes yes no
-`CloudSigma (API v2.0)`_ yes yes yes yes yes yes yes yes no
-`CloudStack`_ yes yes yes yes no no yes yes yes
-`DigitalOcean`_ yes yes yes yes no no yes yes no
-`DimensionData`_ yes yes yes yes yes yes yes yes yes
-`Amazon EC2`_ yes yes yes yes yes yes yes yes yes
-`EquinixMetal`_ yes yes yes yes yes yes yes yes no
-`Eucalyptus`_ yes yes yes yes yes yes yes yes yes
-`Exoscale`_ yes yes yes yes no no yes yes yes
-`Gandi`_ yes yes yes yes no no yes yes no
-`Google Compute Engine`_ yes yes yes yes yes yes yes yes yes
-`GiG G8 Node Provider`_ yes yes yes yes yes yes yes yes no
-`Gridscale`_ yes yes yes yes yes no yes no yes
-`Ikoula`_ yes yes yes yes no no yes yes yes
-`InternetSolutions`_ yes yes yes yes yes yes yes yes yes
-`Kamatera`_ yes yes yes yes yes yes yes yes yes
-`KTUCloud`_ yes yes yes yes no no yes yes yes
-`kubevirt`_ yes yes yes yes yes yes yes yes no
-`Libvirt`_ yes no yes yes yes yes no no no
-`Linode`_ yes yes yes yes yes yes yes yes no
-`Maxihost`_ yes yes yes yes yes yes yes yes no
-`Nimbus`_ yes yes yes yes yes yes yes yes yes
-`NTTAmerica`_ yes yes yes yes yes yes yes yes yes
-`NTTC-CIS`_ yes yes yes yes yes yes yes yes yes
-`OnApp`_ yes yes no yes no no yes no no
-`OpenNebula (v3.8)`_ yes yes yes yes no no yes yes no
-`OpenStack`_ yes no yes yes yes yes yes yes no
-`Outscale API`_ yes yes yes yes yes yes yes no no
-`Outscale INC`_ yes yes yes yes yes yes yes yes yes
-`Outscale SAS`_ yes yes yes yes yes yes yes yes yes
-`Ovh`_ yes yes no yes no no yes yes yes
-`Rackspace Cloud (Next Gen)`_ yes yes yes yes yes yes yes yes yes
-`Rackspace Cloud (First Gen)`_ yes yes yes yes yes yes yes yes yes
-`RimuHosting`_ yes yes yes yes no no yes yes yes
-`Scaleway`_ yes yes yes yes no no yes yes no
-`vCloud`_ yes yes yes yes no no yes yes yes
-`Upcloud`_ yes yes yes yes no no yes yes yes
-`VCL`_ yes yes no yes no no yes yes no
-`vCloud`_ yes yes yes yes no no yes yes yes
-`vps.net`_ yes yes yes yes no no yes yes no
-`VMware vSphere`_ yes yes yes yes yes yes yes yes no
-`Vultr`_ yes yes yes yes yes yes yes yes no
-===================================== ========== =========== =========== ============ ========== ========= =========== ========== ===========
+============================== ========== =========== =========== ============ ========== ========= =========== ========== ===========
+Provider list nodes create node reboot node destroy node start node stop node list images list sizes deploy node
+============================== ========== =========== =========== ============ ========== ========= =========== ========== ===========
+`Abiquo`_ yes yes yes yes no no yes yes no
+`Aliyun ECS`_ yes yes yes yes yes yes yes yes yes
+`PCextreme AuroraCompute`_ yes yes yes yes no no yes yes yes
+`Azure Virtual machines`_ yes yes yes yes no no yes yes yes
+`Azure Virtual machines`_ yes yes yes yes yes yes yes yes yes
+`Brightbox`_ yes yes no yes no no yes yes no
+`Cloudscale`_ yes yes yes yes yes yes yes yes no
+`CloudSigma (API v2.0)`_ yes yes yes yes yes yes yes yes no
+`CloudStack`_ yes yes yes yes no no yes yes yes
+`DigitalOcean`_ yes yes yes yes no no yes yes no
+`DimensionData`_ yes yes yes yes yes yes yes yes yes
+`Amazon EC2`_ yes yes yes yes yes yes yes yes yes
+`EquinixMetal`_ yes yes yes yes yes yes yes yes no
+`Eucalyptus`_ yes yes yes yes yes yes yes yes yes
+`Exoscale`_ yes yes yes yes no no yes yes yes
+`Gandi`_ yes yes yes yes no no yes yes no
+`Google Compute Engine`_ yes yes yes yes yes yes yes yes yes
+`GiG G8 Node Provider`_ yes yes yes yes yes yes yes yes no
+`Gridscale`_ yes yes yes yes yes no yes no yes
+`Ikoula`_ yes yes yes yes no no yes yes yes
+`InternetSolutions`_ yes yes yes yes yes yes yes yes yes
+`Kamatera`_ yes yes yes yes yes yes yes yes yes
+`KTUCloud`_ yes yes yes yes no no yes yes yes
+`kubevirt`_ yes yes yes yes yes yes yes yes no
+`Libvirt`_ yes no yes yes yes yes no no no
+`Linode`_ yes yes yes yes yes yes yes yes no
+`Maxihost`_ yes yes yes yes yes yes yes yes no
+`Nimbus`_ yes yes yes yes yes yes yes yes yes
+`NTTAmerica`_ yes yes yes yes yes yes yes yes yes
+`NTTC-CIS`_ yes yes yes yes yes yes yes yes yes
+`OnApp`_ yes yes no yes no no yes no no
+`OpenNebula (v3.8)`_ yes yes yes yes no no yes yes no
+`OpenStack`_ yes no yes yes yes yes yes yes no
+`Outscale API`_ yes yes yes yes yes yes yes no no
+`Outscale INC`_ yes yes yes yes yes yes yes yes yes
+`Outscale SAS`_ yes yes yes yes yes yes yes yes yes
+`Ovh`_ yes yes no yes no no yes yes yes
+`Rackspace Cloud (Next Gen)`_ yes yes yes yes yes yes yes yes yes
+`Rackspace Cloud (First Gen)`_ yes yes yes yes yes yes yes yes yes
+`RimuHosting`_ yes yes yes yes no no yes yes yes
+`Scaleway`_ yes yes yes yes no no yes yes no
+`vCloud`_ yes yes yes yes no no yes yes yes
+`Upcloud`_ yes yes yes yes no no yes yes yes
+`VCL`_ yes yes no yes no no yes yes no
+`vCloud`_ yes yes yes yes no no yes yes yes
+`vps.net`_ yes yes yes yes no no yes yes no
+`VMware vSphere`_ yes yes yes yes yes yes yes yes no
+`Vultr`_ yes yes yes yes yes yes yes yes no
+============================== ========== =========== =========== ============ ========== ========= =========== ========== ===========
.. _`Abiquo`: http://www.abiquo.com/
.. _`Aliyun ECS`: https://www.aliyun.com/product/ecs
diff --git a/docs/compute/_supported_providers.rst b/docs/compute/_supported_providers.rst
index 9c05ce5..353ae00 100644
--- a/docs/compute/_supported_providers.rst
+++ b/docs/compute/_supported_providers.rst
@@ -1,57 +1,57 @@
.. NOTE: This file has been generated automatically using generate_provider_feature_matrix_table.py script, don't manually edit it
-===================================== ================================================= =================== ======================================================================================================================================================================================================================================================================================================== ================================================= ====================================
-Provider Documentation Provider Constant Supported Regions Module Class Name
-===================================== ================================================= =================== ======================================================================================================================================================================================================================================================================================================== ================================================= ====================================
-`Abiquo`_ ABIQUO single region driver :mod:`libcloud.compute.drivers.abiquo` :class:`AbiquoNodeDriver`
-`Aliyun ECS`_ :doc:`Click </compute/drivers/aliyun_ecs>` ALIYUN_ECS single region driver :mod:`libcloud.compute.drivers.ecs` :class:`ECSDriver`
-`PCextreme AuroraCompute`_ :doc:`Click </compute/drivers/auroracompute>` AURORACOMPUTE single region driver :mod:`libcloud.compute.drivers.auroracompute` :class:`AuroraComputeNodeDriver`
-`Azure Virtual machines`_ :doc:`Click </compute/drivers/azure>` AZURE single region driver :mod:`libcloud.compute.drivers.azure` :class:`AzureNodeDriver`
-`Azure Virtual machines`_ :doc:`Click </compute/drivers/azure_arm>` AZURE_ARM single region driver :mod:`libcloud.compute.drivers.azure_arm` :class:`AzureNodeDriver`
-`Brightbox`_ BRIGHTBOX single region driver :mod:`libcloud.compute.drivers.brightbox` :class:`BrightboxNodeDriver`
-`Cloudscale`_ :doc:`Click </compute/drivers/cloudscale>` CLOUDSCALE single region driver :mod:`libcloud.compute.drivers.cloudscale` :class:`CloudscaleNodeDriver`
-`CloudSigma (API v2.0)`_ :doc:`Click </compute/drivers/cloudsigma>` CLOUDSIGMA single region driver :mod:`libcloud.compute.drivers.cloudsigma` :class:`CloudSigmaNodeDriver`
-`CloudStack`_ :doc:`Click </compute/drivers/cloudstack>` CLOUDSTACK single region driver :mod:`libcloud.compute.drivers.cloudstack` :class:`CloudStackNodeDriver`
-`DigitalOcean`_ :doc:`Click </compute/drivers/digital_ocean>` DIGITAL_OCEAN single region driver :mod:`libcloud.compute.drivers.digitalocean` :class:`DigitalOceanNodeDriver`
-`DimensionData`_ :doc:`Click </compute/drivers/dimensiondata>` DIMENSIONDATA single region driver :mod:`libcloud.compute.drivers.dimensiondata` :class:`DimensionDataNodeDriver`
-`Amazon EC2`_ :doc:`Click </compute/drivers/ec2>` EC2 af-south-1, ap-east-1, ap-northeast-1, ap-northeast-2, ap-northeast-3, ap-south-1, ap-southeast-1, ap-southeast-2, ca-central-1, cn-north-1, cn-northwest-1, eu-central-1, eu-north-1, eu-south-1, eu-west-1, eu-west-2, eu-west-3, sa-east-1, us-east-1, us-east-2, us-gov-west-1, us-west-1, us-west-2 :mod:`libcloud.compute.drivers.ec2` :class:`EC2NodeDriver`
-`EquinixMetal`_ :doc:`Click </compute/drivers/equinixmetal>` EQUINIXMETAL single region driver :mod:`libcloud.compute.drivers.equinixmetal` :class:`EquinixMetalNodeDriver`
-`Eucalyptus`_ EUCALYPTUS single region driver :mod:`libcloud.compute.drivers.ec2` :class:`EucNodeDriver`
-`Exoscale`_ :doc:`Click </compute/drivers/exoscale>` EXOSCALE single region driver :mod:`libcloud.compute.drivers.exoscale` :class:`ExoscaleNodeDriver`
-`Gandi`_ :doc:`Click </compute/drivers/gandi>` GANDI single region driver :mod:`libcloud.compute.drivers.gandi` :class:`GandiNodeDriver`
-`Google Compute Engine`_ :doc:`Click </compute/drivers/gce>` GCE single region driver :mod:`libcloud.compute.drivers.gce` :class:`GCENodeDriver`
-`GiG G8 Node Provider`_ GIG_G8 single region driver :mod:`libcloud.compute.drivers.gig_g8` :class:`G8NodeDriver`
-`Gridscale`_ :doc:`Click </compute/drivers/gridscale>` GRIDSCALE single region driver :mod:`libcloud.compute.drivers.gridscale` :class:`GridscaleNodeDriver`
-`Ikoula`_ :doc:`Click </compute/drivers/ikoula>` IKOULA single region driver :mod:`libcloud.compute.drivers.ikoula` :class:`IkoulaNodeDriver`
-`InternetSolutions`_ :doc:`Click </compute/drivers/internetsolutions>` INTERNETSOLUTIONS single region driver :mod:`libcloud.compute.drivers.internetsolutions` :class:`InternetSolutionsNodeDriver`
-`Kamatera`_ :doc:`Click </compute/drivers/kamatera>` KAMATERA single region driver :mod:`libcloud.compute.drivers.kamatera` :class:`KamateraNodeDriver`
-`KTUCloud`_ KTUCLOUD single region driver :mod:`libcloud.compute.drivers.ktucloud` :class:`KTUCloudNodeDriver`
-`kubevirt`_ KUBEVIRT single region driver :mod:`libcloud.compute.drivers.kubevirt` :class:`KubeVirtNodeDriver`
-`Libvirt`_ :doc:`Click </compute/drivers/libvirt>` LIBVIRT single region driver :mod:`libcloud.compute.drivers.libvirt_driver` :class:`LibvirtNodeDriver`
-`Linode`_ LINODE single region driver :mod:`libcloud.compute.drivers.linode` :class:`LinodeNodeDriver`
-`Maxihost`_ :doc:`Click </compute/drivers/maxihost>` MAXIHOST single region driver :mod:`libcloud.compute.drivers.maxihost` :class:`MaxihostNodeDriver`
-`Nimbus`_ :doc:`Click </compute/drivers/nimbus>` NIMBUS single region driver :mod:`libcloud.compute.drivers.ec2` :class:`NimbusNodeDriver`
-`NTTAmerica`_ :doc:`Click </compute/drivers/ntta>` NTTA single region driver :mod:`libcloud.compute.drivers.ntta` :class:`NTTAmericaNodeDriver`
-`NTTC-CIS`_ :doc:`Click </compute/drivers/nttcis>` NTTCIS single region driver :mod:`libcloud.compute.drivers.nttcis` :class:`NttCisNodeDriver`
-`OnApp`_ :doc:`Click </compute/drivers/onapp>` ONAPP single region driver :mod:`libcloud.compute.drivers.onapp` :class:`OnAppNodeDriver`
-`OpenNebula (v3.8)`_ OPENNEBULA single region driver :mod:`libcloud.compute.drivers.opennebula` :class:`OpenNebulaNodeDriver`
-`OpenStack`_ :doc:`Click </compute/drivers/openstack>` OPENSTACK single region driver :mod:`libcloud.compute.drivers.openstack` :class:`OpenStackNodeDriver`
-`Outscale API`_ :doc:`Click </compute/drivers/outscale>` OUTSCALE single region driver :mod:`libcloud.compute.drivers.outscale` :class:`OutscaleNodeDriver`
-`Outscale INC`_ :doc:`Click </compute/drivers/outscale_inc>` OUTSCALE_INC single region driver :mod:`libcloud.compute.drivers.ec2` :class:`OutscaleINCNodeDriver`
-`Outscale SAS`_ :doc:`Click </compute/drivers/outscale_sas>` OUTSCALE_SAS single region driver :mod:`libcloud.compute.drivers.ec2` :class:`OutscaleSASNodeDriver`
-`Ovh`_ :doc:`Click </compute/drivers/ovh>` OVH ca, eu :mod:`libcloud.compute.drivers.ovh` :class:`OvhNodeDriver`
-`Rackspace Cloud (Next Gen)`_ :doc:`Click </compute/drivers/rackspace>` RACKSPACE single region driver :mod:`libcloud.compute.drivers.rackspace` :class:`RackspaceNodeDriver`
-`Rackspace Cloud (First Gen)`_ RACKSPACE_FIRST_GEN single region driver :mod:`libcloud.compute.drivers.rackspace` :class:`RackspaceFirstGenNodeDriver`
-`RimuHosting`_ RIMUHOSTING single region driver :mod:`libcloud.compute.drivers.rimuhosting` :class:`RimuHostingNodeDriver`
-`Scaleway`_ :doc:`Click </compute/drivers/scaleway>` SCALEWAY single region driver :mod:`libcloud.compute.drivers.scaleway` :class:`ScalewayNodeDriver`
-`vCloud`_ TERREMARK single region driver :mod:`libcloud.compute.drivers.vcloud` :class:`TerremarkDriver`
-`Upcloud`_ :doc:`Click </compute/drivers/upcloud>` UPCLOUD single region driver :mod:`libcloud.compute.drivers.upcloud` :class:`UpcloudDriver`
-`VCL`_ VCL single region driver :mod:`libcloud.compute.drivers.vcl` :class:`VCLNodeDriver`
-`vCloud`_ :doc:`Click </compute/drivers/vcloud>` VCLOUD single region driver :mod:`libcloud.compute.drivers.vcloud` :class:`VCloudNodeDriver`
-`vps.net`_ VPSNET single region driver :mod:`libcloud.compute.drivers.vpsnet` :class:`VPSNetNodeDriver`
-`VMware vSphere`_ :doc:`Click </compute/drivers/vsphere>` VSPHERE single region driver :mod:`libcloud.compute.drivers.vsphere` :class:`VSphereNodeDriver`
-`Vultr`_ :doc:`Click </compute/drivers/vultr>` VULTR single region driver :mod:`libcloud.compute.drivers.vultr` :class:`VultrNodeDriver`
-===================================== ================================================= =================== ======================================================================================================================================================================================================================================================================================================== ================================================= ====================================
+============================== ================================================= =================== ======================================================================================================================================================================================================================================================================================================== ================================================= ====================================
+Provider Documentation Provider Constant Supported Regions Module Class Name
+============================== ================================================= =================== ======================================================================================================================================================================================================================================================================================================== ================================================= ====================================
+`Abiquo`_ ABIQUO single region driver :mod:`libcloud.compute.drivers.abiquo` :class:`AbiquoNodeDriver`
+`Aliyun ECS`_ :doc:`Click </compute/drivers/aliyun_ecs>` ALIYUN_ECS single region driver :mod:`libcloud.compute.drivers.ecs` :class:`ECSDriver`
+`PCextreme AuroraCompute`_ :doc:`Click </compute/drivers/auroracompute>` AURORACOMPUTE single region driver :mod:`libcloud.compute.drivers.auroracompute` :class:`AuroraComputeNodeDriver`
+`Azure Virtual machines`_ :doc:`Click </compute/drivers/azure>` AZURE single region driver :mod:`libcloud.compute.drivers.azure` :class:`AzureNodeDriver`
+`Azure Virtual machines`_ :doc:`Click </compute/drivers/azure_arm>` AZURE_ARM single region driver :mod:`libcloud.compute.drivers.azure_arm` :class:`AzureNodeDriver`
+`Brightbox`_ BRIGHTBOX single region driver :mod:`libcloud.compute.drivers.brightbox` :class:`BrightboxNodeDriver`
+`Cloudscale`_ :doc:`Click </compute/drivers/cloudscale>` CLOUDSCALE single region driver :mod:`libcloud.compute.drivers.cloudscale` :class:`CloudscaleNodeDriver`
+`CloudSigma (API v2.0)`_ :doc:`Click </compute/drivers/cloudsigma>` CLOUDSIGMA single region driver :mod:`libcloud.compute.drivers.cloudsigma` :class:`CloudSigmaNodeDriver`
+`CloudStack`_ :doc:`Click </compute/drivers/cloudstack>` CLOUDSTACK single region driver :mod:`libcloud.compute.drivers.cloudstack` :class:`CloudStackNodeDriver`
+`DigitalOcean`_ :doc:`Click </compute/drivers/digital_ocean>` DIGITAL_OCEAN single region driver :mod:`libcloud.compute.drivers.digitalocean` :class:`DigitalOceanNodeDriver`
+`DimensionData`_ :doc:`Click </compute/drivers/dimensiondata>` DIMENSIONDATA single region driver :mod:`libcloud.compute.drivers.dimensiondata` :class:`DimensionDataNodeDriver`
+`Amazon EC2`_ :doc:`Click </compute/drivers/ec2>` EC2 af-south-1, ap-east-1, ap-northeast-1, ap-northeast-2, ap-northeast-3, ap-south-1, ap-southeast-1, ap-southeast-2, ca-central-1, cn-north-1, cn-northwest-1, eu-central-1, eu-north-1, eu-south-1, eu-west-1, eu-west-2, eu-west-3, sa-east-1, us-east-1, us-east-2, us-gov-west-1, us-west-1, us-west-2 :mod:`libcloud.compute.drivers.ec2` :class:`EC2NodeDriver`
+`EquinixMetal`_ :doc:`Click </compute/drivers/equinixmetal>` EQUINIXMETAL single region driver :mod:`libcloud.compute.drivers.equinixmetal` :class:`EquinixMetalNodeDriver`
+`Eucalyptus`_ EUCALYPTUS single region driver :mod:`libcloud.compute.drivers.ec2` :class:`EucNodeDriver`
+`Exoscale`_ :doc:`Click </compute/drivers/exoscale>` EXOSCALE single region driver :mod:`libcloud.compute.drivers.exoscale` :class:`ExoscaleNodeDriver`
+`Gandi`_ :doc:`Click </compute/drivers/gandi>` GANDI single region driver :mod:`libcloud.compute.drivers.gandi` :class:`GandiNodeDriver`
+`Google Compute Engine`_ :doc:`Click </compute/drivers/gce>` GCE single region driver :mod:`libcloud.compute.drivers.gce` :class:`GCENodeDriver`
+`GiG G8 Node Provider`_ GIG_G8 single region driver :mod:`libcloud.compute.drivers.gig_g8` :class:`G8NodeDriver`
+`Gridscale`_ :doc:`Click </compute/drivers/gridscale>` GRIDSCALE single region driver :mod:`libcloud.compute.drivers.gridscale` :class:`GridscaleNodeDriver`
+`Ikoula`_ :doc:`Click </compute/drivers/ikoula>` IKOULA single region driver :mod:`libcloud.compute.drivers.ikoula` :class:`IkoulaNodeDriver`
+`InternetSolutions`_ :doc:`Click </compute/drivers/internetsolutions>` INTERNETSOLUTIONS single region driver :mod:`libcloud.compute.drivers.internetsolutions` :class:`InternetSolutionsNodeDriver`
+`Kamatera`_ :doc:`Click </compute/drivers/kamatera>` KAMATERA single region driver :mod:`libcloud.compute.drivers.kamatera` :class:`KamateraNodeDriver`
+`KTUCloud`_ KTUCLOUD single region driver :mod:`libcloud.compute.drivers.ktucloud` :class:`KTUCloudNodeDriver`
+`kubevirt`_ KUBEVIRT single region driver :mod:`libcloud.compute.drivers.kubevirt` :class:`KubeVirtNodeDriver`
+`Libvirt`_ :doc:`Click </compute/drivers/libvirt>` LIBVIRT single region driver :mod:`libcloud.compute.drivers.libvirt_driver` :class:`LibvirtNodeDriver`
+`Linode`_ LINODE single region driver :mod:`libcloud.compute.drivers.linode` :class:`LinodeNodeDriver`
+`Maxihost`_ :doc:`Click </compute/drivers/maxihost>` MAXIHOST single region driver :mod:`libcloud.compute.drivers.maxihost` :class:`MaxihostNodeDriver`
+`Nimbus`_ :doc:`Click </compute/drivers/nimbus>` NIMBUS single region driver :mod:`libcloud.compute.drivers.ec2` :class:`NimbusNodeDriver`
+`NTTAmerica`_ :doc:`Click </compute/drivers/ntta>` NTTA single region driver :mod:`libcloud.compute.drivers.ntta` :class:`NTTAmericaNodeDriver`
+`NTTC-CIS`_ :doc:`Click </compute/drivers/nttcis>` NTTCIS single region driver :mod:`libcloud.compute.drivers.nttcis` :class:`NttCisNodeDriver`
+`OnApp`_ :doc:`Click </compute/drivers/onapp>` ONAPP single region driver :mod:`libcloud.compute.drivers.onapp` :class:`OnAppNodeDriver`
+`OpenNebula (v3.8)`_ OPENNEBULA single region driver :mod:`libcloud.compute.drivers.opennebula` :class:`OpenNebulaNodeDriver`
+`OpenStack`_ :doc:`Click </compute/drivers/openstack>` OPENSTACK single region driver :mod:`libcloud.compute.drivers.openstack` :class:`OpenStackNodeDriver`
+`Outscale API`_ :doc:`Click </compute/drivers/outscale>` OUTSCALE single region driver :mod:`libcloud.compute.drivers.outscale` :class:`OutscaleNodeDriver`
+`Outscale INC`_ :doc:`Click </compute/drivers/outscale_inc>` OUTSCALE_INC single region driver :mod:`libcloud.compute.drivers.ec2` :class:`OutscaleINCNodeDriver`
+`Outscale SAS`_ :doc:`Click </compute/drivers/outscale_sas>` OUTSCALE_SAS single region driver :mod:`libcloud.compute.drivers.ec2` :class:`OutscaleSASNodeDriver`
+`Ovh`_ :doc:`Click </compute/drivers/ovh>` OVH ca, eu :mod:`libcloud.compute.drivers.ovh` :class:`OvhNodeDriver`
+`Rackspace Cloud (Next Gen)`_ :doc:`Click </compute/drivers/rackspace>` RACKSPACE single region driver :mod:`libcloud.compute.drivers.rackspace` :class:`RackspaceNodeDriver`
+`Rackspace Cloud (First Gen)`_ RACKSPACE_FIRST_GEN single region driver :mod:`libcloud.compute.drivers.rackspace` :class:`RackspaceFirstGenNodeDriver`
+`RimuHosting`_ RIMUHOSTING single region driver :mod:`libcloud.compute.drivers.rimuhosting` :class:`RimuHostingNodeDriver`
+`Scaleway`_ :doc:`Click </compute/drivers/scaleway>` SCALEWAY single region driver :mod:`libcloud.compute.drivers.scaleway` :class:`ScalewayNodeDriver`
+`vCloud`_ TERREMARK single region driver :mod:`libcloud.compute.drivers.vcloud` :class:`TerremarkDriver`
+`Upcloud`_ :doc:`Click </compute/drivers/upcloud>` UPCLOUD single region driver :mod:`libcloud.compute.drivers.upcloud` :class:`UpcloudDriver`
+`VCL`_ VCL single region driver :mod:`libcloud.compute.drivers.vcl` :class:`VCLNodeDriver`
+`vCloud`_ :doc:`Click </compute/drivers/vcloud>` VCLOUD single region driver :mod:`libcloud.compute.drivers.vcloud` :class:`VCloudNodeDriver`
+`vps.net`_ VPSNET single region driver :mod:`libcloud.compute.drivers.vpsnet` :class:`VPSNetNodeDriver`
+`VMware vSphere`_ :doc:`Click </compute/drivers/vsphere>` VSPHERE single region driver :mod:`libcloud.compute.drivers.vsphere` :class:`VSphereNodeDriver`
+`Vultr`_ :doc:`Click </compute/drivers/vultr>` VULTR single region driver :mod:`libcloud.compute.drivers.vultr` :class:`VultrNodeDriver`
+============================== ================================================= =================== ======================================================================================================================================================================================================================================================================================================== ================================================= ====================================
.. _`Abiquo`: http://www.abiquo.com/
.. _`Aliyun ECS`: https://www.aliyun.com/product/ecs
diff --git a/docs/dns/_supported_methods.rst b/docs/dns/_supported_methods.rst
index cd296e8..168a30f 100644
--- a/docs/dns/_supported_methods.rst
+++ b/docs/dns/_supported_methods.rst
@@ -1,34 +1,34 @@
.. NOTE: This file has been generated automatically using generate_provider_feature_matrix_table.py script, don't manually edit it
-=================== ========== ============ =========== =========== ============= ============= =========== =============
-Provider list zones list records create zone update zone create record update record delete zone delete record
-=================== ========== ============ =========== =========== ============= ============= =========== =============
-`AuroraDNS`_ yes yes yes no yes yes yes yes
-`BuddyNS DNS`_ yes no yes no no no yes no
-`CloudFlare DNS`_ yes yes yes yes yes yes yes yes
-`DigitalOcean`_ yes yes yes no yes yes yes yes
-`DNSimple`_ yes yes yes no yes yes yes yes
-`DurableDNS`_ yes yes yes yes yes yes yes yes
-`Gandi DNS`_ yes yes yes yes yes yes yes yes
-`Gandi LiveDNS`_ yes yes yes no yes yes no yes
-`GoDaddy DNS`_ yes yes no no yes yes yes no
-`Google DNS`_ yes yes yes no yes no yes yes
-`Linode DNS`_ yes yes yes yes yes yes yes yes
-`Liquidweb DNS`_ yes yes yes no yes yes yes yes
-`Luadns`_ yes yes yes no yes no yes yes
-`NFSN DNS`_ no yes no no yes no no yes
-`NS1 DNS`_ yes yes yes no yes yes yes yes
-`OnApp`_ yes yes yes no yes yes yes yes
-`Point DNS`_ yes yes yes yes yes yes yes yes
-`PowerDNS`_ yes yes yes no yes yes yes yes
-`Rackspace DNS`_ yes yes yes yes yes yes yes yes
-`RcodeZero DNS`_ yes yes yes yes yes yes yes yes
-`Route53 DNS`_ yes yes yes no yes yes yes yes
-`Vultr DNS`_ yes yes yes no yes yes yes yes
-`World Wide DNS`_ yes yes yes yes yes yes yes yes
-`Zerigo DNS`_ yes yes yes yes yes yes yes yes
-`Zonomi DNS`_ yes yes yes no yes no yes yes
-=================== ========== ============ =========== =========== ============= ============= =========== =============
+================= ========== ============ =========== =========== ============= ============= =========== =============
+Provider list zones list records create zone update zone create record update record delete zone delete record
+================= ========== ============ =========== =========== ============= ============= =========== =============
+`AuroraDNS`_ yes yes yes no yes yes yes yes
+`BuddyNS DNS`_ yes no yes no no no yes no
+`CloudFlare DNS`_ yes yes yes yes yes yes yes yes
+`DigitalOcean`_ yes yes yes no yes yes yes yes
+`DNSimple`_ yes yes yes no yes yes yes yes
+`DurableDNS`_ yes yes yes yes yes yes yes yes
+`Gandi DNS`_ yes yes yes yes yes yes yes yes
+`Gandi LiveDNS`_ yes yes yes no yes yes no yes
+`GoDaddy DNS`_ yes yes no no yes yes yes no
+`Google DNS`_ yes yes yes no yes no yes yes
+`Linode DNS`_ yes yes yes yes yes yes yes yes
+`Liquidweb DNS`_ yes yes yes no yes yes yes yes
+`Luadns`_ yes yes yes no yes no yes yes
+`NFSN DNS`_ no yes no no yes no no yes
+`NS1 DNS`_ yes yes yes no yes yes yes yes
+`OnApp`_ yes yes yes no yes yes yes yes
+`Point DNS`_ yes yes yes yes yes yes yes yes
+`PowerDNS`_ yes yes yes no yes yes yes yes
+`Rackspace DNS`_ yes yes yes yes yes yes yes yes
+`RcodeZero DNS`_ yes yes yes yes yes yes yes yes
+`Route53 DNS`_ yes yes yes no yes yes yes yes
+`Vultr DNS`_ yes yes yes no yes yes yes yes
+`World Wide DNS`_ yes yes yes yes yes yes yes yes
+`Zerigo DNS`_ yes yes yes yes yes yes yes yes
+`Zonomi DNS`_ yes yes yes no yes no yes yes
+================= ========== ============ =========== =========== ============= ============= =========== =============
.. _`AuroraDNS`: https://www.pcextreme.nl/en/aurora/dns
.. _`BuddyNS DNS`: https://www.buddyns.com
diff --git a/docs/dns/_supported_providers.rst b/docs/dns/_supported_providers.rst
index b05b9d6..39da462 100644
--- a/docs/dns/_supported_providers.rst
+++ b/docs/dns/_supported_providers.rst
@@ -1,34 +1,34 @@
.. NOTE: This file has been generated automatically using generate_provider_feature_matrix_table.py script, don't manually edit it
-=================== ========================================= ================= ==================== ======================================== ==============================
-Provider Documentation Provider Constant Supported Regions Module Class Name
-=================== ========================================= ================= ==================== ======================================== ==============================
-`AuroraDNS`_ :doc:`Click </dns/drivers/auroradns>` AURORADNS single region driver :mod:`libcloud.dns.drivers.auroradns` :class:`AuroraDNSDriver`
-`BuddyNS DNS`_ :doc:`Click </dns/drivers/buddyns>` BUDDYNS single region driver :mod:`libcloud.dns.drivers.buddyns` :class:`BuddyNSDNSDriver`
-`CloudFlare DNS`_ :doc:`Click </dns/drivers/cloudflare>` CLOUDFLARE single region driver :mod:`libcloud.dns.drivers.cloudflare` :class:`CloudFlareDNSDriver`
-`DigitalOcean`_ :doc:`Click </dns/drivers/digital_ocean>` DIGITAL_OCEAN single region driver :mod:`libcloud.dns.drivers.digitalocean` :class:`DigitalOceanDNSDriver`
-`DNSimple`_ :doc:`Click </dns/drivers/dnsimple>` DNSIMPLE single region driver :mod:`libcloud.dns.drivers.dnsimple` :class:`DNSimpleDNSDriver`
-`DurableDNS`_ :doc:`Click </dns/drivers/durabledns>` DURABLEDNS single region driver :mod:`libcloud.dns.drivers.durabledns` :class:`DurableDNSDriver`
-`Gandi DNS`_ GANDI single region driver :mod:`libcloud.dns.drivers.gandi` :class:`GandiDNSDriver`
-`Gandi LiveDNS`_ GANDI_LIVE single region driver :mod:`libcloud.dns.drivers.gandi_live` :class:`GandiLiveDNSDriver`
-`GoDaddy DNS`_ :doc:`Click </dns/drivers/godaddy>` GODADDY single region driver :mod:`libcloud.dns.drivers.godaddy` :class:`GoDaddyDNSDriver`
-`Google DNS`_ :doc:`Click </dns/drivers/google>` GOOGLE single region driver :mod:`libcloud.dns.drivers.google` :class:`GoogleDNSDriver`
-`Linode DNS`_ LINODE single region driver :mod:`libcloud.dns.drivers.linode` :class:`LinodeDNSDriver`
-`Liquidweb DNS`_ :doc:`Click </dns/drivers/liquidweb>` LIQUIDWEB single region driver :mod:`libcloud.dns.drivers.liquidweb` :class:`LiquidWebDNSDriver`
-`Luadns`_ :doc:`Click </dns/drivers/luadns>` LUADNS single region driver :mod:`libcloud.dns.drivers.luadns` :class:`LuadnsDNSDriver`
-`NFSN DNS`_ :doc:`Click </dns/drivers/nfsn>` NFSN single region driver :mod:`libcloud.dns.drivers.nfsn` :class:`NFSNDNSDriver`
-`NS1 DNS`_ NSONE single region driver :mod:`libcloud.dns.drivers.nsone` :class:`NsOneDNSDriver`
-`OnApp`_ :doc:`Click </dns/drivers/onapp>` ONAPP single region driver :mod:`libcloud.dns.drivers.onapp` :class:`OnAppDNSDriver`
-`Point DNS`_ :doc:`Click </dns/drivers/pointdns>` POINTDNS single region driver :mod:`libcloud.dns.drivers.pointdns` :class:`PointDNSDriver`
-`PowerDNS`_ :doc:`Click </dns/drivers/powerdns>` POWERDNS single region driver :mod:`libcloud.dns.drivers.powerdns` :class:`PowerDNSDriver`
-`Rackspace DNS`_ RACKSPACE uk, us :mod:`libcloud.dns.drivers.rackspace` :class:`RackspaceDNSDriver`
-`RcodeZero DNS`_ :doc:`Click </dns/drivers/rcodezero>` RCODEZERO single region driver :mod:`libcloud.dns.drivers.rcodezero` :class:`RcodeZeroDNSDriver`
-`Route53 DNS`_ ROUTE53 single region driver :mod:`libcloud.dns.drivers.route53` :class:`Route53DNSDriver`
-`Vultr DNS`_ :doc:`Click </dns/drivers/vultr>` VULTR single region driver :mod:`libcloud.dns.drivers.vultr` :class:`VultrDNSDriver`
-`World Wide DNS`_ :doc:`Click </dns/drivers/worldwidedns>` WORLDWIDEDNS single region driver :mod:`libcloud.dns.drivers.worldwidedns` :class:`WorldWideDNSDriver`
-`Zerigo DNS`_ ZERIGO single region driver :mod:`libcloud.dns.drivers.zerigo` :class:`ZerigoDNSDriver`
-`Zonomi DNS`_ :doc:`Click </dns/drivers/zonomi>` ZONOMI single region driver :mod:`libcloud.dns.drivers.zonomi` :class:`ZonomiDNSDriver`
-=================== ========================================= ================= ==================== ======================================== ==============================
+================= ========================================= ================= ==================== ======================================== ==============================
+Provider Documentation Provider Constant Supported Regions Module Class Name
+================= ========================================= ================= ==================== ======================================== ==============================
+`AuroraDNS`_ :doc:`Click </dns/drivers/auroradns>` AURORADNS single region driver :mod:`libcloud.dns.drivers.auroradns` :class:`AuroraDNSDriver`
+`BuddyNS DNS`_ :doc:`Click </dns/drivers/buddyns>` BUDDYNS single region driver :mod:`libcloud.dns.drivers.buddyns` :class:`BuddyNSDNSDriver`
+`CloudFlare DNS`_ :doc:`Click </dns/drivers/cloudflare>` CLOUDFLARE single region driver :mod:`libcloud.dns.drivers.cloudflare` :class:`CloudFlareDNSDriver`
+`DigitalOcean`_ :doc:`Click </dns/drivers/digital_ocean>` DIGITAL_OCEAN single region driver :mod:`libcloud.dns.drivers.digitalocean` :class:`DigitalOceanDNSDriver`
+`DNSimple`_ :doc:`Click </dns/drivers/dnsimple>` DNSIMPLE single region driver :mod:`libcloud.dns.drivers.dnsimple` :class:`DNSimpleDNSDriver`
+`DurableDNS`_ :doc:`Click </dns/drivers/durabledns>` DURABLEDNS single region driver :mod:`libcloud.dns.drivers.durabledns` :class:`DurableDNSDriver`
+`Gandi DNS`_ GANDI single region driver :mod:`libcloud.dns.drivers.gandi` :class:`GandiDNSDriver`
+`Gandi LiveDNS`_ GANDI_LIVE single region driver :mod:`libcloud.dns.drivers.gandi_live` :class:`GandiLiveDNSDriver`
+`GoDaddy DNS`_ :doc:`Click </dns/drivers/godaddy>` GODADDY single region driver :mod:`libcloud.dns.drivers.godaddy` :class:`GoDaddyDNSDriver`
+`Google DNS`_ :doc:`Click </dns/drivers/google>` GOOGLE single region driver :mod:`libcloud.dns.drivers.google` :class:`GoogleDNSDriver`
+`Linode DNS`_ LINODE single region driver :mod:`libcloud.dns.drivers.linode` :class:`LinodeDNSDriver`
+`Liquidweb DNS`_ :doc:`Click </dns/drivers/liquidweb>` LIQUIDWEB single region driver :mod:`libcloud.dns.drivers.liquidweb` :class:`LiquidWebDNSDriver`
+`Luadns`_ :doc:`Click </dns/drivers/luadns>` LUADNS single region driver :mod:`libcloud.dns.drivers.luadns` :class:`LuadnsDNSDriver`
+`NFSN DNS`_ :doc:`Click </dns/drivers/nfsn>` NFSN single region driver :mod:`libcloud.dns.drivers.nfsn` :class:`NFSNDNSDriver`
+`NS1 DNS`_ NSONE single region driver :mod:`libcloud.dns.drivers.nsone` :class:`NsOneDNSDriver`
+`OnApp`_ :doc:`Click </dns/drivers/onapp>` ONAPP single region driver :mod:`libcloud.dns.drivers.onapp` :class:`OnAppDNSDriver`
+`Point DNS`_ :doc:`Click </dns/drivers/pointdns>` POINTDNS single region driver :mod:`libcloud.dns.drivers.pointdns` :class:`PointDNSDriver`
+`PowerDNS`_ :doc:`Click </dns/drivers/powerdns>` POWERDNS single region driver :mod:`libcloud.dns.drivers.powerdns` :class:`PowerDNSDriver`
+`Rackspace DNS`_ RACKSPACE uk, us :mod:`libcloud.dns.drivers.rackspace` :class:`RackspaceDNSDriver`
+`RcodeZero DNS`_ :doc:`Click </dns/drivers/rcodezero>` RCODEZERO single region driver :mod:`libcloud.dns.drivers.rcodezero` :class:`RcodeZeroDNSDriver`
+`Route53 DNS`_ ROUTE53 single region driver :mod:`libcloud.dns.drivers.route53` :class:`Route53DNSDriver`
+`Vultr DNS`_ :doc:`Click </dns/drivers/vultr>` VULTR single region driver :mod:`libcloud.dns.drivers.vultr` :class:`VultrDNSDriver`
+`World Wide DNS`_ :doc:`Click </dns/drivers/worldwidedns>` WORLDWIDEDNS single region driver :mod:`libcloud.dns.drivers.worldwidedns` :class:`WorldWideDNSDriver`
+`Zerigo DNS`_ ZERIGO single region driver :mod:`libcloud.dns.drivers.zerigo` :class:`ZerigoDNSDriver`
+`Zonomi DNS`_ :doc:`Click </dns/drivers/zonomi>` ZONOMI single region driver :mod:`libcloud.dns.drivers.zonomi` :class:`ZonomiDNSDriver`
+================= ========================================= ================= ==================== ======================================== ==============================
.. _`AuroraDNS`: https://www.pcextreme.nl/en/aurora/dns
.. _`BuddyNS DNS`: https://www.buddyns.com
diff --git a/docs/examples/container/lxd/example_lxd.py b/docs/examples/container/lxd/example_lxd.py
index 7b8d1bf..55932af 100644
--- a/docs/examples/container/lxd/example_lxd.py
+++ b/docs/examples/container/lxd/example_lxd.py
@@ -123,7 +123,6 @@
def work_with_images():
-
print("Working with images...")
# LXD host change accordingly
diff --git a/libcloud/backup/drivers/dimensiondata.py b/libcloud/backup/drivers/dimensiondata.py
index f7d0f1e..4ea7750 100644
--- a/libcloud/backup/drivers/dimensiondata.py
+++ b/libcloud/backup/drivers/dimensiondata.py
@@ -63,7 +63,6 @@
region=DEFAULT_REGION,
**kwargs,
):
-
if region not in API_ENDPOINTS and host is None:
raise ValueError("Invalid region: %s, no host specified" % (region))
if region is not None:
diff --git a/libcloud/common/aliyun.py b/libcloud/common/aliyun.py
index 84ff648..2414432 100644
--- a/libcloud/common/aliyun.py
+++ b/libcloud/common/aliyun.py
@@ -167,7 +167,6 @@
class SignedAliyunConnection(AliyunConnection):
-
api_version = None
def __init__(
diff --git a/libcloud/common/azure.py b/libcloud/common/azure.py
index 99cff66..cce42df 100644
--- a/libcloud/common/azure.py
+++ b/libcloud/common/azure.py
@@ -191,7 +191,6 @@
retry_failed=None,
*kwargs,
):
-
# Log in again if the token has expired or is going to expire soon
# (next 5 minutes).
if (time.time() + 300) >= int(self.expires_on):
diff --git a/libcloud/common/azure_arm.py b/libcloud/common/azure_arm.py
index 8f849c1..b8caf3a 100644
--- a/libcloud/common/azure_arm.py
+++ b/libcloud/common/azure_arm.py
@@ -209,7 +209,6 @@
return super().connect(**kwargs)
def request(self, action, params=None, data=None, headers=None, method="GET", raw=False):
-
# Log in again if the token has expired or is going to expire soon
# (next 5 minutes).
if (time.time() + 300) >= int(self.expires_on):
diff --git a/libcloud/common/durabledns.py b/libcloud/common/durabledns.py
index ff6b74a..1516409 100644
--- a/libcloud/common/durabledns.py
+++ b/libcloud/common/durabledns.py
@@ -160,7 +160,6 @@
class DurableResponse(XmlResponse):
-
errors = [] # type: List[Dict]
objects = [] # type: List[Dict]
diff --git a/libcloud/common/google.py b/libcloud/common/google.py
index aa79859..1869e2e 100644
--- a/libcloud/common/google.py
+++ b/libcloud/common/google.py
@@ -499,7 +499,6 @@
access_code = None
class AccessCodeReceiver(BaseHTTPRequestHandler):
-
# noinspection PyMethodParameters,PyPep8Naming
def do_GET(self_): # pylint: disable=no-self-argument
query = urlparse.urlparse(self_.path).query
diff --git a/libcloud/common/gridscale.py b/libcloud/common/gridscale.py
index 5582221..1c808f5 100644
--- a/libcloud/common/gridscale.py
+++ b/libcloud/common/gridscale.py
@@ -96,7 +96,6 @@
return r
def get_poll_request_kwargs(self, response, context, request_kwargs):
-
endpoint_url = "requests/{}".format(response.object["request_uuid"])
kwargs = {"action": endpoint_url}
return kwargs
diff --git a/libcloud/common/kubernetes.py b/libcloud/common/kubernetes.py
index 465af7d..f4fadf6 100644
--- a/libcloud/common/kubernetes.py
+++ b/libcloud/common/kubernetes.py
@@ -62,7 +62,6 @@
class KubernetesResponse(JsonResponse):
-
valid_response_codes = [
httplib.OK,
httplib.ACCEPTED,
@@ -93,7 +92,6 @@
cert_file=None,
**kwargs,
):
-
super().__init__(
key_file=key_file,
cert_file=cert_file,
diff --git a/libcloud/common/nttcis.py b/libcloud/common/nttcis.py
index 9519b8c..5d36dfa 100644
--- a/libcloud/common/nttcis.py
+++ b/libcloud/common/nttcis.py
@@ -2293,7 +2293,6 @@
# It is possible to have duplicate element tags.
# If so, convert to a dict of lists
if element.tag.split("}")[1] in self:
-
if isinstance(self[element.tag.split("}")[1]], list):
self[element.tag.split("}")[1]].append(dict(element.items()))
else:
diff --git a/libcloud/common/openstack.py b/libcloud/common/openstack.py
index de0c99e..960b759 100644
--- a/libcloud/common/openstack.py
+++ b/libcloud/common/openstack.py
@@ -357,9 +357,14 @@
return super().morph_action_hook(action)
def _set_up_connection_info(self, url):
+ prev_conn = (self.host, self.port, self.secure)
result = self._tuple_from_url(url)
(self.host, self.port, self.secure, self.request_path) = result
- self.connect()
+ new_conn = (self.host, self.port, self.secure)
+ if new_conn != prev_conn:
+ # We only call connect in case connection details have changed - this way we correctly
+ # re-use connection in case nothing has changed
+ self.connect()
def _populate_hosts_and_request_paths(self):
"""
diff --git a/libcloud/common/types.py b/libcloud/common/types.py
index c5b1732..673e0d9 100644
--- a/libcloud/common/types.py
+++ b/libcloud/common/types.py
@@ -89,7 +89,7 @@
"""The base class for other libcloud exceptions"""
def __init__(self, value, driver=None):
- # type: (str, BaseDriver) -> None
+ # type: (str, Optional[BaseDriver]) -> None
super().__init__(value)
self.value = value
self.driver = driver
diff --git a/libcloud/common/vultr.py b/libcloud/common/vultr.py
index 10f86dc..0415715 100644
--- a/libcloud/common/vultr.py
+++ b/libcloud/common/vultr.py
@@ -38,7 +38,6 @@
class VultrResponse(JsonResponse):
-
objects = None
error_dict = {} # type: Dict[str, str]
errors = None
@@ -55,7 +54,6 @@
}
def __init__(self, response, connection):
-
self.errors = []
super().__init__(response=response, connection=connection)
self.objects, self.errors = self.parse_body_and_errors()
@@ -90,7 +88,6 @@
return VultrException(error["ERRORCODE"], error["ERRORMESSAGE"])
def success(self):
-
return len(self.errors) == 0
diff --git a/libcloud/common/xmlrpc.py b/libcloud/common/xmlrpc.py
index 278fc40..e22d913 100644
--- a/libcloud/common/xmlrpc.py
+++ b/libcloud/common/xmlrpc.py
@@ -53,7 +53,6 @@
class XMLRPCResponse(ErrorCodeMixin, Response):
-
defaultExceptionCls = Exception # type: Type[Exception]
def success(self):
diff --git a/libcloud/compute/base.py b/libcloud/compute/base.py
index ac22a2d..7ec7772 100644
--- a/libcloud/compute/base.py
+++ b/libcloud/compute/base.py
@@ -118,8 +118,8 @@
Mixin class for get_uuid function.
"""
- def __init__(self):
- self._uuid = None # type: str
+ def __init__(self) -> None:
+ self._uuid = None # type: Optional[str]
def get_uuid(self):
"""
@@ -208,10 +208,10 @@
public_ips, # type: List[str]
private_ips, # type: List[str]
driver,
- size=None, # type: NodeSize
- image=None, # type: NodeImage
- extra=None, # type: dict
- created_at=None, # type: datetime.datetime
+ size=None, # type: Optional[NodeSize]
+ image=None, # type: Optional[NodeImage]
+ extra=None, # type: Optional[dict]
+ created_at=None, # type: Optional[datetime.datetime]
):
"""
:param id: Node ID.
@@ -500,7 +500,7 @@
image_id, # type: str
state, # type: NodeImageMemberState
driver, # type: NodeDriver
- created=None, # type: datetime.datetime
+ created=None, # type: Optional[datetime.datetime]
extra=None, # type: Optional[dict]
):
"""
@@ -755,10 +755,10 @@
self,
id, # type: str
driver, # type: NodeDriver
- size=None, # type: int
+ size=None, # type: Optional[int]
extra=None, # type: Optional[Dict]
created=None, # type: Optional[datetime.datetime]
- state=None, # type: StorageVolumeState
+ state=None, # type: Optional[StorageVolumeState]
name=None, # type: Optional[str]
):
# type: (...) -> None
@@ -935,7 +935,7 @@
size, # type: NodeSize
image, # type: NodeImage
location=None, # type: Optional[NodeLocation]
- auth=None, # type: T_Auth
+ auth=None, # type: Optional[T_Auth]
):
# type: (...) -> Node
"""
@@ -1028,11 +1028,11 @@
ssh_timeout=10, # type: int
ssh_key=None, # type: Optional[T_Ssh_key]
ssh_key_password=None, # type: Optional[str]
- auth=None, # type: T_Auth
+ auth=None, # type: Optional[T_Auth]
timeout=SSH_CONNECT_TIMEOUT, # type: int
max_tries=3, # type: int
ssh_interface="public_ips", # type: str
- at_exit_func=None, # type: Callable
+ at_exit_func=None, # type: Optional[Callable]
wait_period=5, # type: int
**create_node_kwargs,
):
diff --git a/libcloud/compute/drivers/azure.py b/libcloud/compute/drivers/azure.py
index 364e0c7..b5c29a1 100644
--- a/libcloud/compute/drivers/azure.py
+++ b/libcloud/compute/drivers/azure.py
@@ -664,7 +664,6 @@
)
if self._is_storage_service_unique(service_name=ex_storage_service_name):
-
self._create_storage_account(
service_name=ex_storage_service_name,
location=_storage_location.service_location,
@@ -888,7 +887,6 @@
return result
def ex_set_instance_endpoints(self, node, endpoints, ex_deployment_slot="Production"):
-
"""
For example::
@@ -1895,7 +1893,6 @@
affinity_group,
extended_properties=None,
):
-
return AzureXmlSerializer.doc_from_data(
"CreateStorageServiceInput",
[
@@ -2249,7 +2246,6 @@
or endpoint.load_balancer_probe.port
or endpoint.load_balancer_probe.protocol
):
-
load_balancer_probe = ET.Element("LoadBalancerProbe")
input_endpoint.append(load_balancer_probe)
AzureXmlSerializer.data_to_xml(
@@ -2295,7 +2291,6 @@
system_configuration_set,
xml,
):
-
AzureXmlSerializer.data_to_xml([("RoleName", role_name)], xml)
AzureXmlSerializer.data_to_xml([("RoleType", role_type)], xml)
@@ -2396,7 +2391,6 @@
vm_image_name,
role_size,
):
-
doc = AzureXmlSerializer.doc_from_xml("PersistentVMRole")
AzureXmlSerializer.role_to_xml(
availability_set_name,
@@ -2459,7 +2453,6 @@
virtual_network_name,
vm_image_name,
):
-
doc = AzureXmlSerializer.doc_from_xml("Deployment")
AzureXmlSerializer.data_to_xml([("Name", deployment_name)], doc)
AzureXmlSerializer.data_to_xml([("DeploymentSlot", deployment_slot)], doc)
@@ -2560,7 +2553,6 @@
@staticmethod
def extended_properties_dict_to_xml_fragment(extended_properties):
-
if extended_properties is not None and len(extended_properties) > 0:
xml = ET.Element("ExtendedProperties")
for key, val in extended_properties.items():
@@ -2595,7 +2587,6 @@
class WindowsAzureDataTypedList(WindowsAzureData):
-
list_type = None
xml_element_name = None
diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py
index bb99926..432ccf3 100644
--- a/libcloud/compute/drivers/azure_arm.py
+++ b/libcloud/compute/drivers/azure_arm.py
@@ -25,7 +25,7 @@
import binascii
from libcloud.utils import iso8601
-from libcloud.utils.py3 import basestring
+from libcloud.utils.py3 import parse_qs, urlparse, basestring
from libcloud.common.types import LibcloudError
from libcloud.compute.base import (
Node,
@@ -64,6 +64,13 @@
VM_EXTENSION_API_VERSION = "2015-06-15"
VM_SIZE_API_VERSION = "2015-06-15" # this API is deprecated
+# If pagination code in the list_nodes() method has still not completed after this mount of
+# seconds, we will break early from while True loop to avoid infinite loop under edge conditions.
+# Keep in mind that we want this timeout relatively high since each `_to_node()` method call which
+# is called for each node can result in additional HTTP requests (to retrieve power state, nics,
+# etc).
+LIST_NODES_PAGINATION_TIMEOUT = 300
+
class AzureImage(NodeImage):
"""Represents a Marketplace node image that an Azure VM can boot from."""
@@ -456,8 +463,10 @@
:return: list of node objects
:rtype: ``list`` of :class:`.Node`
- """
+ NOTE: With the default arguments, the function may result in M * (1 + (N * 3)) HTTP
+ requests where M is number of API pages and N is number of nodes returned per page.
+ """
if ex_resource_group:
action = (
"/subscriptions/%s/resourceGroups/%s/"
@@ -468,11 +477,25 @@
action = "/subscriptions/%s/providers/Microsoft.Compute/" "virtualMachines" % (
self.subscription_id
)
- r = self.connection.request(action, params={"api-version": VM_API_VERSION})
- return [
- self._to_node(n, fetch_nic=ex_fetch_nic, fetch_power_state=ex_fetch_power_state)
- for n in r.object["value"]
- ]
+ params = {"api-version": VM_API_VERSION}
+
+ now_ts = int(time.time())
+ deadline_ts = now_ts + LIST_NODES_PAGINATION_TIMEOUT
+
+ nodes = []
+ while time.time() < deadline_ts:
+ r = self.connection.request(action, params=params)
+ nodes.extend(
+ self._to_node(n, fetch_nic=ex_fetch_nic, fetch_power_state=ex_fetch_power_state)
+ for n in r.object["value"]
+ )
+ if not r.object.get("nextLink"):
+ # No next page
+ break
+ parsed_next_link = urlparse.urlparse(r.object["nextLink"])
+ params.update({k: v[0] for k, v in parse_qs(parsed_next_link.query).items()})
+ action = parsed_next_link.path
+ return nodes
def create_node(
self,
diff --git a/libcloud/compute/drivers/cloudstack.py b/libcloud/compute/drivers/cloudstack.py
index e6c6b34..b92895d 100644
--- a/libcloud/compute/drivers/cloudstack.py
+++ b/libcloud/compute/drivers/cloudstack.py
@@ -44,7 +44,6 @@
try:
return int(value)
except ValueError as e:
-
if str(value).lower() == "unlimited":
return -1
@@ -467,7 +466,6 @@
start_port=None,
end_port=None,
):
-
"""
A Firewall rule.
@@ -530,7 +528,6 @@
start_port=None,
end_port=None,
):
-
"""
A egress firewall rule.
@@ -1383,7 +1380,6 @@
imgs = self._sync_request(command="listTemplates", params=args, method="GET")
images = []
for img in imgs.get("template", []):
-
extra = {
"hypervisor": img["hypervisor"],
"format": img["format"],
@@ -2114,7 +2110,6 @@
networks = []
for vpc in vpcs:
-
networks.append(
CloudStackVPC(
vpc["name"],
@@ -2146,7 +2141,6 @@
routers = []
for router in rts:
-
routers.append(
CloudStackRouter(
router["id"],
@@ -4206,7 +4200,6 @@
return True
def ex_detach_nic_from_node(self, nic, node):
-
"""
Remove Nic from a VM
diff --git a/libcloud/compute/drivers/dimensiondata.py b/libcloud/compute/drivers/dimensiondata.py
index dca4b18..1d0148a 100644
--- a/libcloud/compute/drivers/dimensiondata.py
+++ b/libcloud/compute/drivers/dimensiondata.py
@@ -120,7 +120,6 @@
region=DEFAULT_REGION,
**kwargs,
):
-
if region not in API_ENDPOINTS and host is None:
raise ValueError("Invalid region: %s, no host specified" % (region))
if region is not None:
@@ -2723,7 +2722,6 @@
value_required=None,
display_on_report=None,
):
-
"""
Modify a specific tag key
@@ -3720,7 +3718,6 @@
ex_tagid_value_pairs=None,
ex_tagname_value_pairs=None,
):
-
"""
This MCP 2.0 only function deploys a new Cloud Server from a
CloudControl compatible Server Image, which does not utilize
diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py
index 9a3e2ea..506e6f6 100644
--- a/libcloud/compute/drivers/ec2.py
+++ b/libcloud/compute/drivers/ec2.py
@@ -3048,7 +3048,6 @@
try:
results.append(self.connection.request(self.path, params=params.copy()).object)
except Exception as e:
-
if e.args[0].find("InvalidPermission.Duplicate") == -1:
raise e
return results
@@ -3346,7 +3345,6 @@
for node_id in node_instance_ids:
nodes_elastic_ip_mappings.setdefault(node_id, [])
for addr in self._to_addresses(result, only_associated):
-
instance_id = addr.instance_id
if node_id == instance_id:
@@ -4397,7 +4395,6 @@
]
def _to_image(self, element):
-
id = findtext(element=element, xpath="imageId", namespace=NAMESPACE)
name = findtext(element=element, xpath="name", namespace=NAMESPACE)
@@ -4410,7 +4407,6 @@
xpath="billingProducts/item/billingProduct",
namespace=NAMESPACE,
):
-
billing_products.append(p.text)
# Get our tags
@@ -4764,7 +4760,6 @@
for item in findall(
element=element, xpath="privateIpAddressesSet/item", namespace=NAMESPACE
):
-
priv_ips.append(
{
"private_ip": findtext(
@@ -5968,7 +5963,6 @@
return is_truncated, quota
def _to_product_type(self, elem):
-
productTypeId = findtext(element=elem, xpath="productTypeId", namespace=OUTSCALE_NAMESPACE)
description = findtext(element=elem, xpath="description", namespace=OUTSCALE_NAMESPACE)
@@ -6001,7 +5995,6 @@
return product_type
def _to_product_types(self, elem):
-
product_types = []
for product_types_item in findall(
element=elem, xpath="productTypeSet/item", namespace=OUTSCALE_NAMESPACE
@@ -6044,7 +6037,6 @@
return product_types
def _to_instance_types(self, elem):
-
instance_types = []
for instance_types_item in findall(
element=elem, xpath="instanceTypeSet/item", namespace=OUTSCALE_NAMESPACE
diff --git a/libcloud/compute/drivers/gce.py b/libcloud/compute/drivers/gce.py
index c8a140a..49b50c2 100644
--- a/libcloud/compute/drivers/gce.py
+++ b/libcloud/compute/drivers/gce.py
@@ -496,7 +496,6 @@
capacity_scaler=1,
description=None,
):
-
if isinstance(instance_group, GCEInstanceGroup):
self.instance_group = instance_group
elif isinstance(instance_group, GCEInstanceGroupManager):
diff --git a/libcloud/compute/drivers/gridscale.py b/libcloud/compute/drivers/gridscale.py
index 479ea0b..c68c482 100644
--- a/libcloud/compute/drivers/gridscale.py
+++ b/libcloud/compute/drivers/gridscale.py
@@ -650,7 +650,6 @@
return True
else:
-
return False
def import_key_pair_from_string(self, name, key_material):
diff --git a/libcloud/compute/drivers/internetsolutions.py b/libcloud/compute/drivers/internetsolutions.py
index b668f8e..32cc424 100644
--- a/libcloud/compute/drivers/internetsolutions.py
+++ b/libcloud/compute/drivers/internetsolutions.py
@@ -47,7 +47,6 @@
region=DEFAULT_REGION,
**kwargs,
):
-
if region not in API_ENDPOINTS:
raise ValueError("Invalid region: %s" % (region))
diff --git a/libcloud/compute/drivers/kubevirt.py b/libcloud/compute/drivers/kubevirt.py
index e5f8b4a..a76293d 100644
--- a/libcloud/compute/drivers/kubevirt.py
+++ b/libcloud/compute/drivers/kubevirt.py
@@ -438,7 +438,6 @@
data = json.dumps(vm)
req = KUBEVIRT_URL + "namespaces/" + namespace + "/virtualmachines/"
try:
-
self.connection.request(req, method=method, data=data)
except Exception:
@@ -486,7 +485,6 @@
return namespaces
def list_sizes(self, location=None):
-
namespace = ""
if location:
namespace = location.name
@@ -678,7 +676,6 @@
raise
if result.object["status"]["phase"] != "Bound":
for _ in range(3):
-
req = ROOT_URL + "namespaces/" + namespace + "/persistentvolumeclaims/" + name
try:
result = self.connection.request(req).object
@@ -861,7 +858,6 @@
raise
def ex_list_persistent_volume_claims(self, namespace="default"):
-
pvc_req = ROOT_URL + "namespaces/" + namespace + "/persistentvolumeclaims"
try:
result = self.connection.request(pvc_req).object
@@ -871,7 +867,6 @@
return pvcs
def ex_list_storage_classes(self):
-
# sc = storage class
sc_req = "/apis/storage.k8s.io/v1/storageclasses"
try:
@@ -940,7 +935,6 @@
if "memory" in vm["spec"]["template"]["spec"]["domain"]["resources"]["limits"]:
memory = vm["spec"]["template"]["spec"]["domain"]["resources"]["limits"]["memory"]
elif vm["spec"]["template"]["spec"]["domain"]["resources"].get("requests", None):
-
if vm["spec"]["template"]["spec"]["domain"]["resources"]["requests"].get(
"memory", None
):
diff --git a/libcloud/compute/drivers/linode.py b/libcloud/compute/drivers/linode.py
index 2df7000..50f2fef 100644
--- a/libcloud/compute/drivers/linode.py
+++ b/libcloud/compute/drivers/linode.py
@@ -799,7 +799,6 @@
class LinodeNodeDriverV4(LinodeNodeDriver):
-
connectionCls = LinodeConnectionV4
_linode_disk_filesystems = LINODE_DISK_FILESYSTEMS_V4
diff --git a/libcloud/compute/drivers/ntta.py b/libcloud/compute/drivers/ntta.py
index 04de2cc..f47d2fc 100644
--- a/libcloud/compute/drivers/ntta.py
+++ b/libcloud/compute/drivers/ntta.py
@@ -47,7 +47,6 @@
region=DEFAULT_REGION,
**kwargs,
):
-
if region not in API_ENDPOINTS:
raise ValueError("Invalid region: %s" % (region))
diff --git a/libcloud/compute/drivers/nttcis.py b/libcloud/compute/drivers/nttcis.py
index 040e468..a0d8286 100644
--- a/libcloud/compute/drivers/nttcis.py
+++ b/libcloud/compute/drivers/nttcis.py
@@ -123,7 +123,6 @@
region=DEFAULT_REGION,
**kwargs,
):
-
if region not in API_ENDPOINTS and host is None:
raise ValueError("Invalid region: %s, no host specified" % (region))
if region is not None:
@@ -3256,7 +3255,6 @@
value_required=None,
display_on_report=None,
):
-
"""
Modify a specific tag key
@@ -4282,7 +4280,6 @@
ex_tagid_value_pairs=None,
ex_tagname_value_pairs=None,
):
-
"""
This MCP 2.0 only function deploys a new Cloud Server from a
CloudControl compatible Server Image, which does not utilize
diff --git a/libcloud/compute/drivers/outscale.py b/libcloud/compute/drivers/outscale.py
index 8b7b737..ea8eb76 100644
--- a/libcloud/compute/drivers/outscale.py
+++ b/libcloud/compute/drivers/outscale.py
@@ -7743,22 +7743,25 @@
)
def _to_volumes(self, volumes):
- return [self._to_volumes(volume) for volume in volumes]
+ return [self._to_volume(volume) for volume in volumes]
def _to_node(self, vm):
name = ""
private_ips = []
+ if "PrivateIp" in vm:
+ private_ips = [vm["PrivateIp"]]
+ public_ips = []
+ if "PublicIp" in vm:
+ public_ips = [vm["PublicIp"]]
for tag in vm["Tags"]:
if tag["Key"] == "Name":
name = tag["Value"]
- if "Nics" in vm:
- private_ips = vm["Nics"]["PrivateIps"]
return Node(
id=vm["VmId"],
name=name,
state=self.NODE_STATE[vm["State"]],
- public_ips=[],
+ public_ips=public_ips,
private_ips=private_ips,
driver=self,
extra=vm,
diff --git a/libcloud/compute/drivers/vsphere.py b/libcloud/compute/drivers/vsphere.py
index 692248a..3c4e457 100644
--- a/libcloud/compute/drivers/vsphere.py
+++ b/libcloud/compute/drivers/vsphere.py
@@ -1200,7 +1200,6 @@
]
def __init__(self, key, secret=None, secure=True, host=None, port=443, ca_cert=None):
-
if not key or not secret:
raise InvalidCredsError("Please provide both username " "(key) and password (secret).")
super().__init__(key=key, secure=secure, host=host, port=port)
@@ -1550,7 +1549,6 @@
ex_filter_datacenters=None,
ex_filter_connection_states=None,
):
-
kwargs = {
"filter.folders": ex_filter_folders,
"filter.names": ex_filter_names,
@@ -1782,7 +1780,6 @@
return images
def ex_list_networks(self):
-
request = "/rest/vcenter/network"
response = self._request(request).object["value"]
networks = []
@@ -1950,7 +1947,6 @@
)
elif image.extra["type"] == "vm-template":
-
tp_request = "/rest/vcenter/vm-template/library-items/" + image.id
template = self._request(tp_request).object["value"]
spec = {}
diff --git a/libcloud/container/base.py b/libcloud/container/base.py
index 1ec7148..b684a6d 100644
--- a/libcloud/container/base.py
+++ b/libcloud/container/base.py
@@ -41,8 +41,8 @@
state, # type: ContainerState
ip_addresses, # type: List[str]
driver, # type: ContainerDriver
- extra=None, # type: dict
- created_at=None, # type: str
+ extra=None, # type: Optional[dict]
+ created_at=None, # type: Optional[str]
):
"""
:param id: Container id.
@@ -112,7 +112,7 @@
path, # type: str
version, # type: str
driver, # type: ContainerDriver
- extra=None, # type: dict
+ extra=None, # type: Optional[dict]
):
"""
:param id: Container Image id.
@@ -164,7 +164,7 @@
id, # type: str
name, # type: str
driver, # type: ContainerDriver
- extra=None, # type: dict
+ extra=None, # type: Optional[dict]
):
"""
:param id: Container Image id.
diff --git a/libcloud/container/drivers/docker.py b/libcloud/container/drivers/docker.py
index a202c4e..4f64176 100644
--- a/libcloud/container/drivers/docker.py
+++ b/libcloud/container/drivers/docker.py
@@ -41,7 +41,6 @@
class DockerResponse(JsonResponse):
-
valid_response_codes = [
httplib.OK,
httplib.ACCEPTED,
@@ -102,7 +101,6 @@
class DockerConnection(ConnectionUserAndKey):
-
responseCls = DockerResponse
timeout = 60
@@ -120,7 +118,6 @@
class DockertlsConnection(KeyCertificateConnection):
-
responseCls = DockerResponse
def __init__(
@@ -134,7 +131,6 @@
cert_file="",
**kwargs,
):
-
super().__init__(
key_file=key_file,
cert_file=cert_file,
@@ -167,7 +163,6 @@
self.cert_file = cert_file
def add_default_headers(self, headers):
-
headers["Content-Type"] = "application/json"
return headers
diff --git a/libcloud/container/drivers/lxd.py b/libcloud/container/drivers/lxd.py
index 3841d31..46e3c33 100644
--- a/libcloud/container/drivers/lxd.py
+++ b/libcloud/container/drivers/lxd.py
@@ -158,7 +158,6 @@
"""
def __init__(self, name, driver, used_by, config, managed):
-
# the name of the storage pool
self.name = name
@@ -216,7 +215,6 @@
@classmethod
def build_from_response(cls, metadata):
-
server_info = LXDServerInfo()
server_info.api_extensions = metadata.get("api_extensions", None)
server_info.api_status = metadata.get("api_status", None)
@@ -228,7 +226,6 @@
return server_info
def __init__(self):
-
# List of API extensions added after
# the API was marked stable
self.api_extensions = None
@@ -278,7 +275,6 @@
]
def parse_body(self):
-
if len(self.body) == 0 and not self.parse_zero_length_body:
return self.body
@@ -334,7 +330,6 @@
class LXDtlsConnection(KeyCertificateConnection):
-
responseCls = LXDResponse
def __init__(
@@ -350,7 +345,6 @@
certificate_validator=None,
**kwargs,
):
-
if certificate_validator is not None:
certificate_validator(key_file=key_file, cert_file=cert_file)
else:
@@ -419,9 +413,7 @@
ca_cert=None,
certificate_validator=check_certificates,
):
-
if key_file:
-
if not cert_file:
# LXD tls authentication-
# We pass two files, a key_file with the
@@ -467,7 +459,6 @@
self.version = self._get_api_version()
def build_operation_websocket_url(self, uuid, w_secret):
-
uri = "wss://%s:%s/%s/operations/%s/" "websocket?secret=%s" % (
self.connection.host,
self.connection.port,
@@ -524,7 +515,6 @@
ex_instance_type=None,
ex_timeout=default_time_out,
):
-
"""
Create a new container
Authentication: trusted
@@ -579,7 +569,6 @@
parameters = json.loads(parameters)
if parameters["source"].get("mode", None) == "pull":
-
try:
# this means the image must be downloaded
image = self.install_image(path=None, ex_timeout=ex_timeout, **parameters)
@@ -623,7 +612,6 @@
return container
def get_container(self, id, ex_get_ip_addr=True):
-
"""
Get a container by ID
@@ -748,7 +736,6 @@
)
def ex_freeze_container(self, container, ex_timeout=default_time_out):
-
"""
Set the given container into a freeze state
@@ -770,7 +757,6 @@
)
def ex_unfreeze_container(self, container, ex_timeout=default_time_out):
-
"""
Set the given container into unfreeze state
@@ -819,14 +805,12 @@
raise self._get_lxd_api_exception_for_error(err)
try:
-
# wait until the timeout...but util getting here the operation
# may have finished already
id = response_dict["metadata"]["id"]
req = "/{}/operations/{}/wait?timeout={}".format(self.version, id, ex_timeout)
response = self.connection.request(req)
except BaseHTTPError as err:
-
lxd_exception = self._get_lxd_api_exception_for_error(err)
# if not found assume the operation completed
if lxd_exception.message != "not found":
@@ -952,7 +936,6 @@
)
elif input["wait-for-websocket"] is True and input["interactive"] is True:
-
return LXDContainerExecuteResult(
uuid=uuid,
secret_0=fds["0"],
@@ -964,7 +947,6 @@
)
elif input["interactive"] is False and input["record-output"] is True:
-
output = response_dict["metadata"]["metadata"]["output"]
result = response_dict["metadata"]["metadata"]["result"]
return LXDContainerExecuteResult(
@@ -978,7 +960,6 @@
)
else:
-
result = response_dict["metadata"]["metadata"]["result"]
return LXDContainerExecuteResult(
uuid=uuid,
@@ -1054,7 +1035,6 @@
return self._to_image(metadata=response_dict["metadata"])
def install_image(self, path, ex_timeout=default_time_out, **ex_img_data):
-
"""
Install a container image from a remote path. Not that the
path currently is not used. Image data should be provided
@@ -1101,14 +1081,12 @@
assert_response(response_dict=response_dict, status_code=100)
try:
-
# wait until the timeout...but until getting here the operation
# may have finished already
id = response_dict["metadata"]["id"]
req = "/{}/operations/{}/wait?timeout={}".format(self.version, id, ex_timeout)
response = self.connection.request(req)
except BaseHTTPError as err:
-
lxd_exception = self._get_lxd_api_exception_for_error(err)
# if not found assume the operation completed
if lxd_exception.message != "not found":
@@ -1234,7 +1212,6 @@
return self._to_storage_pool(data=response_dict["metadata"])
def ex_create_storage_pool(self, definition):
-
"""
Create a storage_pool from definition.
@@ -1338,7 +1315,6 @@
type = volume[-2]
if not detailed:
-
metadata = {
"config": {"size": None},
"name": name,
@@ -1393,7 +1369,6 @@
pools = response_dict["metadata"]
for pool in pools:
-
pool_id = pool.split("/")[-1]
volumes = self.ex_list_storage_pool_volumes(pool_id=pool_id)
@@ -1405,7 +1380,6 @@
return None
def create_volume(self, pool_id, definition, **kwargs):
-
"""
Create a new storage volume on a given storage pool
Operation: sync or async (when copying an existing volume)
@@ -1460,14 +1434,12 @@
assert_response(response_dict=response_dict, status_code=100)
try:
-
# wait until the timeout...but util getting here the operation
# may have finished already
oid = response_dict["metadata"]["id"]
req = "/{}/operations/{}/wait?timeout={}".format(self.version, oid, ex_timeout)
response = self.connection.request(req)
except BaseHTTPError as err:
-
lxd_exception = self._get_lxd_api_exception_for_error(err)
# if not found assume the operation completed
if lxd_exception.message != "not found":
@@ -1517,7 +1489,6 @@
"""
try:
-
req = "/{}/storage-pools/{}/volumes/{}/{}".format(
self.version,
pool_id,
diff --git a/libcloud/container/drivers/rancher.py b/libcloud/container/drivers/rancher.py
index 8bf423d..1e68d5f 100644
--- a/libcloud/container/drivers/rancher.py
+++ b/libcloud/container/drivers/rancher.py
@@ -66,7 +66,6 @@
class RancherConnection(ConnectionUserAndKey):
-
responseCls = RancherResponse
timeout = 30
diff --git a/libcloud/dns/base.py b/libcloud/dns/base.py
index a358b92..f878447 100644
--- a/libcloud/dns/base.py
+++ b/libcloud/dns/base.py
@@ -36,7 +36,7 @@
type, # type: str
ttl, # type: int
driver, # type: DNSDriver
- extra=None, # type: dict
+ extra=None, # type: Optional[dict]
):
"""
:param id: Zone id.
@@ -116,8 +116,8 @@
data, # type: str
zone, # type: Zone
driver, # type: DNSDriver
- ttl=None, # type: int
- extra=None, # type: dict
+ ttl=None, # type: Optional[int]
+ extra=None, # type: Optional[dict]
):
"""
:param id: Record id
diff --git a/libcloud/dns/drivers/cloudflare.py b/libcloud/dns/drivers/cloudflare.py
index 12d2db5..7cf02eb 100644
--- a/libcloud/dns/drivers/cloudflare.py
+++ b/libcloud/dns/drivers/cloudflare.py
@@ -200,7 +200,6 @@
MEMBERSHIPS_PAGE_SIZE = 50
def __init__(self, key, secret=None, secure=True, host=None, port=None, **kwargs):
-
if secret is None:
self.connectionCls = TokenDNSConnection
diff --git a/libcloud/dns/drivers/linode.py b/libcloud/dns/drivers/linode.py
index 45d7480..b2f609f 100644
--- a/libcloud/dns/drivers/linode.py
+++ b/libcloud/dns/drivers/linode.py
@@ -87,7 +87,6 @@
api_version=DEFAULT_API_VERSION,
**kwargs,
):
-
if cls is LinodeDNSDriver:
if api_version == "3.0":
cls = LinodeDNSDriverV3
diff --git a/libcloud/dns/drivers/vultr.py b/libcloud/dns/drivers/vultr.py
index e147f59..bdff9bd 100644
--- a/libcloud/dns/drivers/vultr.py
+++ b/libcloud/dns/drivers/vultr.py
@@ -93,7 +93,6 @@
class VultrDNSDriverV1(VultrDNSDriver):
-
connectionCls = VultrDNSConnection
RECORD_TYPE_MAP = {
diff --git a/libcloud/loadbalancer/drivers/alb.py b/libcloud/loadbalancer/drivers/alb.py
index 34286f4..8ab3ea4 100644
--- a/libcloud/loadbalancer/drivers/alb.py
+++ b/libcloud/loadbalancer/drivers/alb.py
@@ -68,7 +68,6 @@
balancers=[],
members=[],
):
-
self.id = target_group_id
self.name = name
self.protocol = protocol
@@ -135,7 +134,6 @@
ssl_certificate="",
rules=[],
):
-
self.id = listener_id
self.protocol = protocol
self.port = port
@@ -186,7 +184,6 @@
conditions={},
listener=None,
):
-
self.id = rule_id
self.is_default = is_default
self.priority = priority
@@ -882,7 +879,6 @@
]
def _to_target_group(self, el):
-
target_group = ALBTargetGroup(
target_group_id=findtext(element=el, xpath="TargetGroupArn", namespace=NS),
name=findtext(element=el, xpath="TargetGroupName", namespace=NS),
diff --git a/libcloud/loadbalancer/drivers/dimensiondata.py b/libcloud/loadbalancer/drivers/dimensiondata.py
index 6ff379f..11644d4 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -78,7 +78,6 @@
region=DEFAULT_REGION,
**kwargs,
):
-
if region not in API_ENDPOINTS and host is None:
raise ValueError("Invalid region: %s, no host specified" % (region))
if region is not None:
diff --git a/libcloud/loadbalancer/drivers/gce.py b/libcloud/loadbalancer/drivers/gce.py
index 1351119..9fa5eec 100644
--- a/libcloud/loadbalancer/drivers/gce.py
+++ b/libcloud/loadbalancer/drivers/gce.py
@@ -36,7 +36,6 @@
_VALUE_TO_ALGORITHM_MAP = {"RANDOM": Algorithm.RANDOM}
def __init__(self, *args, **kwargs):
-
if kwargs.get("gce_driver"):
self.gce = kwargs["gce_driver"]
else:
diff --git a/libcloud/loadbalancer/drivers/nttcis.py b/libcloud/loadbalancer/drivers/nttcis.py
index 9f66042..ecd1499 100644
--- a/libcloud/loadbalancer/drivers/nttcis.py
+++ b/libcloud/loadbalancer/drivers/nttcis.py
@@ -82,7 +82,6 @@
region=DEFAULT_REGION,
**kwargs,
):
-
self.network_domain_id = network_domain_id
if region not in API_ENDPOINTS and host is None:
diff --git a/libcloud/pricing.py b/libcloud/pricing.py
index 836cc5d..496eccb 100644
--- a/libcloud/pricing.py
+++ b/libcloud/pricing.py
@@ -193,7 +193,6 @@
def get_image_price(driver_name, image_name, size_name=None, cores=1):
-
# for now only images of GCE have pricing data
if driver_name == "gce_images":
return _get_gce_image_price(image_name=image_name, size_name=size_name, cores=cores)
@@ -221,6 +220,7 @@
:rtype: ``float``
:return: Image price
"""
+
# helper function to get image family for gce images
def _get_gce_image_family(image_name):
image_family = None
diff --git a/libcloud/storage/drivers/azure_blobs.py b/libcloud/storage/drivers/azure_blobs.py
index 763cbb8..1fafbe9 100644
--- a/libcloud/storage/drivers/azure_blobs.py
+++ b/libcloud/storage/drivers/azure_blobs.py
@@ -1221,7 +1221,6 @@
file_path,
headers,
):
-
headers = headers or {}
lease.update_headers(headers)
diff --git a/libcloud/storage/drivers/backblaze_b2.py b/libcloud/storage/drivers/backblaze_b2.py
index 25b45f3..3ea8311 100644
--- a/libcloud/storage/drivers/backblaze_b2.py
+++ b/libcloud/storage/drivers/backblaze_b2.py
@@ -554,7 +554,6 @@
def _perform_upload(
self, data, container, object_name, extra=None, verify_hash=True, headers=None
):
-
if isinstance(data, str):
data = bytearray(data)
diff --git a/libcloud/storage/drivers/cloudfiles.py b/libcloud/storage/drivers/cloudfiles.py
index 9f749b4..c126c11 100644
--- a/libcloud/storage/drivers/cloudfiles.py
+++ b/libcloud/storage/drivers/cloudfiles.py
@@ -192,23 +192,19 @@
def get_endpoint(self):
region = self._ex_force_service_region.upper()
- if self.use_internal_url:
- endpoint_type = "internal"
- else:
- endpoint_type = "external"
-
if "2.0" in self._auth_version:
ep = self.service_catalog.get_endpoint(
service_type="object-store",
name="cloudFiles",
region=region,
- endpoint_type=endpoint_type,
+ endpoint_type="internal" if self.use_internal_url else "external",
)
cdn_ep = self.service_catalog.get_endpoint(
service_type="rax:object-cdn",
name="cloudFilesCDN",
region=region,
- endpoint_type=endpoint_type,
+ # Cloud Files has no concept of an "internal" CDN.
+ endpoint_type="external",
)
else:
raise LibcloudError('Auth version "%s" not supported' % (self._auth_version))
diff --git a/libcloud/storage/drivers/digitalocean_spaces.py b/libcloud/storage/drivers/digitalocean_spaces.py
index f898fe9..5e0bc7b 100644
--- a/libcloud/storage/drivers/digitalocean_spaces.py
+++ b/libcloud/storage/drivers/digitalocean_spaces.py
@@ -49,7 +49,6 @@
backoff=None,
**kwargs,
):
-
super().__init__(
user_id,
key,
@@ -82,7 +81,6 @@
backoff=None,
**kwargs,
):
-
super().__init__(
user_id,
key,
@@ -115,7 +113,6 @@
region=DO_SPACES_DEFAULT_REGION,
**kwargs,
):
-
if region not in DO_SPACES_HOSTS_BY_REGION:
raise LibcloudError("Unknown region (%s)" % (region), driver=self)
diff --git a/libcloud/storage/drivers/minio.py b/libcloud/storage/drivers/minio.py
index 0d42931..a1bafdd 100644
--- a/libcloud/storage/drivers/minio.py
+++ b/libcloud/storage/drivers/minio.py
@@ -39,7 +39,6 @@
backoff=None,
**kwargs,
):
-
super().__init__(
user_id,
key,
diff --git a/libcloud/storage/drivers/oss.py b/libcloud/storage/drivers/oss.py
index a3aa4b4..b43cdaa 100644
--- a/libcloud/storage/drivers/oss.py
+++ b/libcloud/storage/drivers/oss.py
@@ -545,7 +545,6 @@
body = response.parse_body()
# pylint: disable=maybe-no-member
for node in body.findall(fixxpath(xpath="Upload", namespace=self.namespace)):
-
key = finder(node, "Key")
upload_id = finder(node, "UploadId")
initiated = finder(node, "Initiated")
@@ -884,7 +883,7 @@
root = Element("CompleteMultipartUpload")
- for (count, etag) in chunks:
+ for count, etag in chunks:
part = SubElement(root, "Part")
part_no = SubElement(part, "PartNumber")
part_no.text = str(count)
diff --git a/libcloud/storage/drivers/rgw.py b/libcloud/storage/drivers/rgw.py
index 088c988..ba8caed 100644
--- a/libcloud/storage/drivers/rgw.py
+++ b/libcloud/storage/drivers/rgw.py
@@ -56,7 +56,6 @@
backoff=None,
**kwargs,
):
-
super().__init__(
user_id,
key,
@@ -89,7 +88,6 @@
backoff=None,
**kwargs,
):
-
super().__init__(
user_id,
key,
@@ -120,7 +118,6 @@
region=S3_RGW_DEFAULT_REGION,
**kwargs,
):
-
if host is None:
raise LibcloudError("host required", driver=self)
diff --git a/libcloud/storage/drivers/s3.py b/libcloud/storage/drivers/s3.py
index 31ef851..a46a7bd 100644
--- a/libcloud/storage/drivers/s3.py
+++ b/libcloud/storage/drivers/s3.py
@@ -725,7 +725,7 @@
"""
root = Element("CompleteMultipartUpload")
- for (count, etag) in chunks:
+ for count, etag in chunks:
part = SubElement(root, "Part")
part_no = SubElement(part, "PartNumber")
part_no.text = str(count)
@@ -1107,7 +1107,16 @@
"""
headers = {}
storage_class = storage_class or "standard"
- if storage_class not in ["standard", "reduced_redundancy"]:
+ if storage_class not in [
+ "standard",
+ "reduced_redundancy",
+ "standard_ia",
+ "onezone_ia",
+ "intelligent_tiering",
+ "glacier",
+ "deep_archive",
+ "glacier_ir",
+ ]:
raise ValueError("Invalid storage class value: %s" % (storage_class))
key = self.http_vendor_prefix + "-storage-class"
diff --git a/libcloud/test/backup/test_dimensiondata_v2_3.py b/libcloud/test/backup/test_dimensiondata_v2_3.py
index eb666cf..46110ed 100644
--- a/libcloud/test/backup/test_dimensiondata_v2_3.py
+++ b/libcloud/test/backup/test_dimensiondata_v2_3.py
@@ -303,7 +303,6 @@
class DimensionDataMockHttp(MockHttp):
-
fixtures = BackupFileFixtures("dimensiondata")
def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers):
diff --git a/libcloud/test/backup/test_dimensiondata_v2_4.py b/libcloud/test/backup/test_dimensiondata_v2_4.py
index 939a6b5..2156c42 100644
--- a/libcloud/test/backup/test_dimensiondata_v2_4.py
+++ b/libcloud/test/backup/test_dimensiondata_v2_4.py
@@ -303,7 +303,6 @@
class DimensionDataMockHttp(MockHttp):
-
fixtures = BackupFileFixtures("dimensiondata")
def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers):
diff --git a/libcloud/test/common/test_cloudstack.py b/libcloud/test/common/test_cloudstack.py
index 631680b..ad49df9 100644
--- a/libcloud/test/common/test_cloudstack.py
+++ b/libcloud/test/common/test_cloudstack.py
@@ -117,7 +117,6 @@
class CloudStackMockHttp(MockHttp, unittest.TestCase):
-
ERROR_TEXT = "ERROR TEXT"
def _response(self, status, result, response):
diff --git a/libcloud/test/common/test_google.py b/libcloud/test/common/test_google.py
index 0b4250c..4303f44 100644
--- a/libcloud/test/common/test_google.py
+++ b/libcloud/test/common/test_google.py
@@ -357,7 +357,6 @@
class GoogleOAuth2CredentialTest(GoogleTestCase):
-
_ia_get_code_patcher = mock.patch(
"libcloud.common.google.GoogleInstalledAppAuthConnection.get_code",
return_value=1234,
diff --git a/libcloud/test/common/test_openstack.py b/libcloud/test/common/test_openstack.py
index e10a7a1..2bfeb76 100644
--- a/libcloud/test/common/test_openstack.py
+++ b/libcloud/test/common/test_openstack.py
@@ -76,6 +76,47 @@
raw=False,
)
+ @patch("libcloud.test.common.test_openstack.OpenStackBaseConnection.connect", Mock())
+ def test_connection_is_reused_when_details_dont_change(self):
+ url = "https://example.com"
+
+ self.connection._set_up_connection_info(url=url)
+ self.assertEqual(self.connection.connect.call_count, 1)
+
+ for index in range(0, 10):
+ self.connection._set_up_connection_info(url=url)
+ self.assertEqual(self.connection.connect.call_count, 1)
+
+ @patch("libcloud.test.common.test_openstack.OpenStackBaseConnection.connect", Mock())
+ def test_connection_is_not_reused_when_details_change(self):
+ url = "https://example.com"
+ self.connection._set_up_connection_info(url=url)
+ self.assertEqual(self.connection.connect.call_count, 1)
+
+ url = "https://example.com"
+ self.connection._set_up_connection_info(url=url)
+ self.assertEqual(self.connection.connect.call_count, 1)
+
+ url = "https://example.com:80"
+ self.connection._set_up_connection_info(url=url)
+ self.assertEqual(self.connection.connect.call_count, 2)
+
+ url = "http://example.com:80"
+ self.connection._set_up_connection_info(url=url)
+ self.assertEqual(self.connection.connect.call_count, 3)
+
+ url = "http://exxample.com:80"
+ self.connection._set_up_connection_info(url=url)
+ self.assertEqual(self.connection.connect.call_count, 4)
+
+ url = "http://exxample.com:81"
+ self.connection._set_up_connection_info(url=url)
+ self.assertEqual(self.connection.connect.call_count, 5)
+
+ url = "http://exxample.com:81"
+ self.connection._set_up_connection_info(url=url)
+ self.assertEqual(self.connection.connect.call_count, 5)
+
if __name__ == "__main__":
sys.exit(unittest.main())
diff --git a/libcloud/test/common/test_openstack_identity.py b/libcloud/test/common/test_openstack_identity.py
index f8545a3..8f6b550 100644
--- a/libcloud/test/common/test_openstack_identity.py
+++ b/libcloud/test/common/test_openstack_identity.py
@@ -98,8 +98,8 @@
user_id = OPENSTACK_PARAMS[0]
key = OPENSTACK_PARAMS[1]
- for (auth_version, mock_http_class, kwargs) in tuples:
- for (url, url_path) in auth_urls:
+ for auth_version, mock_http_class, kwargs in tuples:
+ for url, url_path in auth_urls:
connection = self._get_mock_connection(
mock_http_class=mock_http_class, auth_url=url
)
@@ -167,7 +167,7 @@
user_id = OPENSTACK_PARAMS[0]
key = OPENSTACK_PARAMS[1]
- for (auth_version, mock_http_class, kwargs) in tuples:
+ for auth_version, mock_http_class, kwargs in tuples:
connection = self._get_mock_connection(mock_http_class=mock_http_class)
auth_url = connection.auth_url
@@ -313,7 +313,7 @@
user_id = OPENSTACK_PARAMS[0]
key = OPENSTACK_PARAMS[1]
- for (auth_version, mock_http_class, kwargs) in tuples:
+ for auth_version, mock_http_class, kwargs in tuples:
mock_http_class.type = None
connection = self._get_mock_connection(mock_http_class=mock_http_class)
auth_url = connection.auth_url
diff --git a/libcloud/test/compute/fixtures/azure_arm/_77777777_7777_7777_7777_777777777777_oauth2_token_PAGINATION_INFINITE_LOOP.json b/libcloud/test/compute/fixtures/azure_arm/_77777777_7777_7777_7777_777777777777_oauth2_token_PAGINATION_INFINITE_LOOP.json
new file mode 100644
index 0000000..b9702f2
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_77777777_7777_7777_7777_777777777777_oauth2_token_PAGINATION_INFINITE_LOOP.json
@@ -0,0 +1 @@
+{"expires_in":"3600","token_type":"Bearer","expires_on":"1111111111","not_before":"1111111111","resource":"https://management.core.windows.net/","access_token":"3333333333333333333333333333333333333333333333333333333"}
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines.json
index 019c5c7..4c40f57 100644
--- a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines.json
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines.json
@@ -52,5 +52,6 @@
"id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/virtualMachines/test-node-1",
"name": "test-node-1"
}
- ]
+ ],
+ "nextLink": "https://management.azure.com:443/subscriptions/99999999-9999-9999-9999-999999999999/providers/Microsoft.Compute/virtualMachines?api-version=2021-11-01&$skiptoken=1!/Subscriptions/99999999-9999-9999-9999-999999999999/ResourceGroups/000000/VMs/DDFEBF64-E92B-4A50-9949-6E44BFC61D4G"
}
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines_1.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines_1.json
new file mode 100644
index 0000000..1b63cd9
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines_1.json
@@ -0,0 +1,56 @@
+{
+ "value": [
+ {
+ "properties": {
+ "vmId": "DDFEBF64-E92B-4A50-9949-6E44BFC61D4G",
+ "additionalCapabilities": {
+ "ultraSSDEnabled": "False",
+ "hibernationEnabled": "False"
+ },
+ "hardwareProfile": {
+ "vmSize": "Standard_A1"
+ },
+ "storageProfile": {
+ "imageReference": {
+ "publisher": "OpenLogic",
+ "offer": "CentOS",
+ "sku": "7.3",
+ "version": "latest"
+ },
+ "osDisk": {
+ "osType": "Linux",
+ "name": "test-node-disk-1",
+ "createOption": "FromImage",
+ "caching": "ReadWrite",
+ "managedDisk": {
+ "storageAccountType": "Standard_LRS",
+ "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-node-disk-2"
+ }
+ },
+ "dataDisks": []
+ },
+ "osProfile": {
+ "computerName": "test-node-2",
+ "adminUsername": "user",
+ "linuxConfiguration": {
+ "disablePasswordAuthentication": false
+ },
+ "secrets": []
+ },
+ "networkProfile": {
+ "networkInterfaces": [
+ {
+ "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Network/networkInterfaces/test-node-2-nic"
+ }
+ ]
+ },
+ "provisioningState": "Running"
+ },
+ "type": "Microsoft.Compute/virtualMachines",
+ "location": "eastus",
+ "tags": {},
+ "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/virtualMachines/test-node-2",
+ "name": "test-node-2"
+ }
+ ]
+}
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines_PAGINATION_INFINITE_LOOP.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines_PAGINATION_INFINITE_LOOP.json
new file mode 100644
index 0000000..8c9e913
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_virtualMachines_PAGINATION_INFINITE_LOOP.json
@@ -0,0 +1,53 @@
+{
+ "value": [
+ {
+ "properties": {
+ "vmId": "CCEEBF63-E92B-4A50-9949-6E44BFC61D3F",
+ "additionalCapabilities": {
+ "ultraSSDEnabled": "False",
+ "hibernationEnabled": "False"
+ },
+ "hardwareProfile": {
+ "vmSize": "Standard_A1"
+ },
+ "storageProfile": {
+ "imageReference": {
+ "publisher": "OpenLogic",
+ "offer": "CentOS",
+ "sku": "7.3",
+ "version": "latest"
+ },
+ "osDisk": {
+ "osType": "Linux",
+ "name": "test-node-disk-1",
+ "createOption": "FromImage",
+ "caching": "ReadWrite",
+ "managedDisk": {
+ "storageAccountType": "Standard_LRS",
+ "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-node-disk-1"
+ }
+ },
+ "dataDisks": []
+ },
+ "osProfile": {
+ "computerName": "test-node-1",
+ "adminUsername": "user",
+ "linuxConfiguration": {
+ "disablePasswordAuthentication": false
+ },
+ "secrets": []
+ },
+ "networkProfile": {
+ "networkInterfaces": []
+ },
+ "provisioningState": "Running"
+ },
+ "type": "Microsoft.Compute/virtualMachines",
+ "location": "eastus",
+ "tags": {},
+ "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/virtualMachines/test-node-1",
+ "name": "test-node-1"
+ }
+ ],
+ "nextLink": "https://management.azure.com:443/subscriptions/99999999-9999-9999-9999-999999999999/providers/Microsoft.Compute/virtualMachines?api-version=2021-11-01&$skiptoken=1!/Subscriptions/99999999-9999-9999-9999-999999999999/ResourceGroups/000000/VMs/DDFEBF64-E92B-4A50-9949-6E44BFC61D4G"
+}
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_2_InstanceView.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_2_InstanceView.json
new file mode 100644
index 0000000..0ac000f
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_resourceGroups_000000_providers_Microsoft_Compute_virtualMachines_test_node_2_InstanceView.json
@@ -0,0 +1,27 @@
+{
+ "vmAgent": {
+ "vmAgentVersion": "2.2.5",
+ "statuses": [
+ {
+ "code": "ProvisioningState/succeeded",
+ "level": "Info",
+ "displayStatus": "Ready",
+ "message": "Guest Agent is running",
+ "time": "2017-03-09T15:11:03+00:00"
+ }
+ ],
+ "extensionHandlers": []
+ },
+ "statuses": [
+ {
+ "code": "ProvisioningState/updating",
+ "level": "Info",
+ "displayStatus": "Updating"
+ },
+ {
+ "code": "PowerState/running",
+ "level": "Info",
+ "displayStatus": "VM running"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_resourceGroups_000000_providers_Microsoft_Network_networkInterfaces_test_node_2_nic.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_resourceGroups_000000_providers_Microsoft_Network_networkInterfaces_test_node_2_nic.json
new file mode 100644
index 0000000..868bb53
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_resourceGroups_000000_providers_Microsoft_Network_networkInterfaces_test_node_2_nic.json
@@ -0,0 +1,38 @@
+{
+ "name": "test-node-2-nic",
+ "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Network/networkInterfaces/test-node-2-nic",
+ "etag": "W/\"5E19562E-8E84-493D-A29E-A84F5AC21D77\"",
+ "location": "eastus",
+ "tags": {},
+ "properties": {
+ "provisioningState": "Succeeded",
+ "resourceGuid": "AD512C3D-9A7B-4012-8C5D-227A9EA5E6F5",
+ "ipConfigurations": [
+ {
+ "name": "myip1",
+ "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Network/networkInterfaces/test-node-2-nic/ipConfigurations/myip2",
+ "etag": "W/\"5E19562E-8E84-493D-A29E-A84F5AC21D77\"",
+ "properties": {
+ "provisioningState": "Succeeded",
+ "privateIPAddress": "10.0.0.2",
+ "privateIPAllocationMethod": "Dynamic",
+ "subnet": {
+ "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Network/virtualNetworks/000000/subnets/000000"
+ },
+ "primary": true
+ }
+ }
+ ],
+ "dnsSettings": {
+ "dnsServers": [],
+ "appliedDnsServers": []
+ },
+ "macAddress": "11-11-11-11-11-11",
+ "enableIPForwarding": false,
+ "primary": true,
+ "virtualMachine": {
+ "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/virtualMachines/test-node-2"
+ }
+ },
+ "type": "Microsoft.Network/networkInterfaces"
+}
\ No newline at end of file
diff --git a/libcloud/test/compute/test_abiquo.py b/libcloud/test/compute/test_abiquo.py
index 3734633..13ae1b8 100644
--- a/libcloud/test/compute/test_abiquo.py
+++ b/libcloud/test/compute/test_abiquo.py
@@ -415,7 +415,6 @@
def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines_3_tasks_b44fe278_6b0f_4dfb_be81_7c03006a93cb(
self, method, url, body, headers
):
-
if headers["Authorization"] == "Basic dGVuOnNoaW4=":
# User 'ten:shin' failed task
response = self.fixtures.load("vdc_4_vapp_6_vm_3_deploy_task_failed.xml")
diff --git a/libcloud/test/compute/test_azure.py b/libcloud/test/compute/test_azure.py
index 5d50b8d..b42507c 100644
--- a/libcloud/test/compute/test_azure.py
+++ b/libcloud/test/compute/test_azure.py
@@ -118,7 +118,6 @@
self.driver.list_nodes(ex_cloud_service_name="dcoddkinztest04")
def test_restart_node_success(self):
-
node = Node(
id="dc03",
name="dc03",
@@ -137,7 +136,6 @@
# simulating attempting to reboot a node that is already rebooting
def test_restart_node_fail_no_deployment(self):
-
node = Node(
id="dc03",
name="dc03",
@@ -155,7 +153,6 @@
)
def test_restart_node_fail_no_cloud_service(self):
-
node = Node(
id="dc03",
name="dc03",
@@ -173,7 +170,6 @@
)
def test_restart_node_fail_node_not_found(self):
-
node = Node(
id="dc13",
name="dc13",
@@ -191,7 +187,6 @@
self.assertFalse(result)
def test_destroy_node_success_single_node_in_cloud_service(self):
-
node = Node(
id="oddkinz1",
name="oddkinz1",
@@ -207,7 +202,6 @@
self.assertTrue(result)
def test_destroy_node_success_multiple_nodes_in_cloud_service(self):
-
node = Node(
id="oddkinz1",
name="oddkinz1",
@@ -223,7 +217,6 @@
self.assertTrue(result)
def test_destroy_node_fail_node_does_not_exist(self):
-
node = Node(
id="oddkinz2",
name="oddkinz2",
@@ -241,7 +234,6 @@
)
def test_destroy_node_success_cloud_service_not_found(self):
-
node = Node(
id="cloudredis",
name="cloudredis",
@@ -354,7 +346,6 @@
class AzureMockHttp(MockHttp):
-
fixtures = ComputeFileFixtures("azure")
def _3761b98b_673d_526c_8d55_fee918758e6e_services_hostedservices_oddkinz1_deploymentslots_Production(
@@ -584,7 +575,6 @@
def _3761b98b_673d_526c_8d55_fee918758e6e_services_hostedservices_testdcabc2_deploymentslots_Production(
self, method, url, body, headers
):
-
if method == "GET":
body = self.fixtures.load(
"_3761b98b_673d_526c_8d55_fee918758e6e_services_hostedservices_testdcabc2_deploymentslots_Production.xml"
@@ -601,7 +591,6 @@
def _3761b98b_673d_526c_8d55_fee918758e6e_operations_acc33f6756cda6fd96826394fce4c9f3(
self, method, url, body, headers
):
-
if method == "GET":
body = self.fixtures.load(
"_3761b98b_673d_526c_8d55_fee918758e6e_operations_acc33f6756cda6fd96826394fce4c9f3.xml"
diff --git a/libcloud/test/compute/test_azure_arm.py b/libcloud/test/compute/test_azure_arm.py
index 85b320d..b81fb24 100644
--- a/libcloud/test/compute/test_azure_arm.py
+++ b/libcloud/test/compute/test_azure_arm.py
@@ -20,7 +20,7 @@
from unittest import mock
from libcloud.test import MockHttp, LibcloudTestCase, unittest
-from libcloud.utils.py3 import httplib
+from libcloud.utils.py3 import httplib, parse_qs, urlparse, urlunquote
from libcloud.common.types import LibcloudError
from libcloud.compute.base import NodeSize, NodeLocation, StorageVolume, VolumeSnapshot
from libcloud.compute.types import Provider, NodeState, StorageVolumeState, VolumeSnapshotState
@@ -36,13 +36,13 @@
class AzureNodeDriverTests(LibcloudTestCase):
-
TENANT_ID = "77777777-7777-7777-7777-777777777777"
SUBSCRIPTION_ID = "99999999"
APPLICATION_ID = "55555555-5555-5555-5555-555555555555"
APPLICATION_PASS = "p4ssw0rd"
def setUp(self):
+ AzureMockHttp.type = None
Azure = get_driver(Provider.AZURE_ARM)
Azure.connectionCls.conn_class = AzureMockHttp
self.driver = Azure(
@@ -445,29 +445,51 @@
def test_list_nodes(self, fps_mock):
nodes = self.driver.list_nodes()
- self.assertEqual(len(nodes), 1)
+ self.assertEqual(len(nodes), 2)
self.assertEqual(nodes[0].name, "test-node-1")
self.assertEqual(nodes[0].state, NodeState.UPDATING)
self.assertEqual(nodes[0].private_ips, ["10.0.0.1"])
self.assertEqual(nodes[0].public_ips, [])
+ self.assertEqual(nodes[1].name, "test-node-2")
+ self.assertEqual(nodes[1].state, NodeState.UPDATING)
+ self.assertEqual(nodes[1].private_ips, ["10.0.0.2"])
+ self.assertEqual(nodes[1].public_ips, [])
+
fps_mock.assert_called()
@mock.patch(
+ "libcloud.compute.drivers.azure_arm.AzureNodeDriver._fetch_power_state",
+ return_value=NodeState.UPDATING,
+ )
+ @mock.patch("libcloud.compute.drivers.azure_arm.LIST_NODES_PAGINATION_TIMEOUT", 1)
+ def test_list_nodes_pagination_timeout_reached(self, fps_mock):
+ # Verify we don't end up in an infinite loop in case server returns a bad response or
+ # similar
+ AzureMockHttp.type = "PAGINATION_INFINITE_LOOP"
+ nodes = self.driver.list_nodes()
+ self.assertTrue(len(nodes) >= 1)
+
+ @mock.patch(
"libcloud.compute.drivers.azure_arm.AzureNodeDriver" "._fetch_power_state",
return_value=NodeState.UPDATING,
)
def test_list_nodes__no_fetch_power_state(self, fps_mock):
nodes = self.driver.list_nodes(ex_fetch_power_state=False)
- self.assertEqual(len(nodes), 1)
+ self.assertEqual(len(nodes), 2)
self.assertEqual(nodes[0].name, "test-node-1")
self.assertNotEqual(nodes[0].state, NodeState.UPDATING)
self.assertEqual(nodes[0].private_ips, ["10.0.0.1"])
self.assertEqual(nodes[0].public_ips, [])
+ self.assertEqual(nodes[1].name, "test-node-2")
+ self.assertNotEqual(nodes[1].state, NodeState.UPDATING)
+ self.assertEqual(nodes[1].private_ips, ["10.0.0.2"])
+ self.assertEqual(nodes[1].public_ips, [])
+
fps_mock.assert_not_called()
def test_create_volume(self):
@@ -677,7 +699,6 @@
self.assertTrue(isinstance(snaps[3].created, datetime))
def test_list_snapshots_in_resource_group(self):
-
snaps = self.driver.list_snapshots(ex_resource_group="111111")
self.assertEqual(len(snaps), 2)
@@ -815,6 +836,11 @@
"99999999_9999_9999_9999_999999999999",
AzureNodeDriverTests.SUBSCRIPTION_ID,
)
+ unquoted_url = urlunquote(url)
+ if "$skiptoken=" in unquoted_url and self.type != "PAGINATION_INFINITE_LOOP":
+ parsed_url = urlparse.urlparse(unquoted_url)
+ params = parse_qs(parsed_url.query)
+ file_name += "_" + params["$skiptoken"][0].split("!")[0]
fixture = self.fixtures.load(file_name + ".json")
if method in ("POST", "PUT"):
diff --git a/libcloud/test/compute/test_cloudsigma_v1_0.py b/libcloud/test/compute/test_cloudsigma_v1_0.py
index d0c3b4d..a0deb3a 100644
--- a/libcloud/test/compute/test_cloudsigma_v1_0.py
+++ b/libcloud/test/compute/test_cloudsigma_v1_0.py
@@ -152,24 +152,19 @@
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
def _servers_62fe7cde_4fb9_4c63_bd8c_e757930066a0_start(self, method, url, body, headers):
-
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
def _servers_62fe7cde_4fb9_4c63_bd8c_e757930066a0_stop(self, method, url, body, headers):
-
return (httplib.NO_CONTENT, body, {}, httplib.responses[httplib.OK])
def _servers_62fe7cde_4fb9_4c63_bd8c_e757930066a0_destroy(self, method, url, body, headers):
-
return (httplib.NO_CONTENT, body, {}, httplib.responses[httplib.NO_CONTENT])
def _drives_d18119ce_7afa_474a_9242_e0384b160220_clone(self, method, url, body, headers):
-
body = self.fixtures.load("drives_clone.txt")
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
def _drives_a814def5_1789_49a0_bf88_7abe7bb1682a_info(self, method, url, body, headers):
-
body = self.fixtures.load("drives_single_info.txt")
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
@@ -197,11 +192,9 @@
return (httplib.NO_CONTENT, body, {}, httplib.responses[httplib.OK])
def _drives_d18119ce_7afa_474a_9242_e0384b160220_destroy(self, method, url, body, headers):
-
return (httplib.NO_CONTENT, body, {}, httplib.responses[httplib.OK])
def _servers_62fe7cde_4fb9_4c63_bd8c_e757930066a0_set(self, method, url, body, headers):
-
body = self.fixtures.load("servers_set.txt")
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
diff --git a/libcloud/test/compute/test_cloudstack.py b/libcloud/test/compute/test_cloudstack.py
index 469e969..6f9907d 100644
--- a/libcloud/test/compute/test_cloudstack.py
+++ b/libcloud/test/compute/test_cloudstack.py
@@ -341,7 +341,6 @@
self.assertEqual(network.extra["project_id"], fixture_network["projectid"])
def test_ex_delete_network(self):
-
network = self.driver.ex_list_networks()[0]
result = self.driver.ex_delete_network(network=network)
@@ -364,7 +363,6 @@
self.assertEqual(nic.mac_address, fixture_nic[i]["macaddress"])
def test_ex_add_nic_to_node(self):
-
vm = self.driver.list_nodes()[0]
network = self.driver.ex_list_networks()[0]
ip = "10.1.4.123"
@@ -373,7 +371,6 @@
self.assertTrue(result)
def test_ex_remove_nic_from_node(self):
-
vm = self.driver.list_nodes()[0]
nic = self.driver.ex_list_nics(node=vm)[0]
@@ -436,7 +433,6 @@
self.assertEqual(vpc.id, fixture_vpc["id"])
def test_ex_delete_vpc(self):
-
vpc = self.driver.ex_list_vpcs()[0]
result = self.driver.ex_delete_vpc(vpc=vpc)
diff --git a/libcloud/test/compute/test_dimensiondata_v2_3.py b/libcloud/test/compute/test_dimensiondata_v2_3.py
index c0befbe..0113de5 100644
--- a/libcloud/test/compute/test_dimensiondata_v2_3.py
+++ b/libcloud/test/compute/test_dimensiondata_v2_3.py
@@ -2198,7 +2198,6 @@
class DimensionDataMockHttp(MockHttp):
-
fixtures = ComputeFileFixtures("dimensiondata")
def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_report_usage(
@@ -3472,7 +3471,6 @@
def _caas_2_3_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_createPortList(
self, method, url, body, headers
):
-
request = ET.fromstring(body)
if request.tag != "{urn:didata.com:api:cloud:types}" "createPortList":
raise InvalidRequestError(request.tag)
@@ -3499,7 +3497,6 @@
def _caas_2_3_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_editPortList(
self, method, url, body, headers
):
-
request = ET.fromstring(body)
if request.tag != "{urn:didata.com:api:cloud:types}" "editPortList":
raise InvalidRequestError(request.tag)
diff --git a/libcloud/test/compute/test_dimensiondata_v2_4.py b/libcloud/test/compute/test_dimensiondata_v2_4.py
index f26cea5..ec4c2b3 100644
--- a/libcloud/test/compute/test_dimensiondata_v2_4.py
+++ b/libcloud/test/compute/test_dimensiondata_v2_4.py
@@ -2294,7 +2294,6 @@
class DimensionDataMockHttp(MockHttp):
-
fixtures = ComputeFileFixtures("dimensiondata")
def _oec_0_9_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_report_usage(
@@ -3572,7 +3571,6 @@
def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_createPortList(
self, method, url, body, headers
):
-
request = ET.fromstring(body)
if request.tag != "{urn:didata.com:api:cloud:types}" "createPortList":
raise InvalidRequestError(request.tag)
@@ -3599,7 +3597,6 @@
def _caas_2_4_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_editPortList(
self, method, url, body, headers
):
-
request = ET.fromstring(body)
if request.tag != "{urn:didata.com:api:cloud:types}" "editPortList":
raise InvalidRequestError(request.tag)
diff --git a/libcloud/test/compute/test_gandi.py b/libcloud/test/compute/test_gandi.py
index f21eab8..19b9832 100644
--- a/libcloud/test/compute/test_gandi.py
+++ b/libcloud/test/compute/test_gandi.py
@@ -28,7 +28,6 @@
class GandiTests(unittest.TestCase):
-
node_name = "test2"
def setUp(self):
@@ -212,7 +211,6 @@
class GandiMockHttp(BaseGandiMockHttp):
-
fixtures = ComputeFileFixtures("gandi")
def _xmlrpc__hosting_datacenter_list(self, method, url, body, headers):
diff --git a/libcloud/test/compute/test_kamatera.py b/libcloud/test/compute/test_kamatera.py
index a42e8e1..ee16fb3 100644
--- a/libcloud/test/compute/test_kamatera.py
+++ b/libcloud/test/compute/test_kamatera.py
@@ -209,7 +209,6 @@
class KamateraMockHttp(MockHttp):
-
fixtures = ComputeFileFixtures("kamatera")
def _service_server(self, method, url, body, headers):
diff --git a/libcloud/test/compute/test_kubevirt.py b/libcloud/test/compute/test_kubevirt.py
index e5afafa..0d89fac 100644
--- a/libcloud/test/compute/test_kubevirt.py
+++ b/libcloud/test/compute/test_kubevirt.py
@@ -24,7 +24,6 @@
class KubeVirtTestCase(unittest.TestCase, KubernetesAuthTestCaseMixin):
-
driver_cls = KubeVirtNodeDriver
fixtures = ComputeFileFixtures("kubevirt")
@@ -84,7 +83,6 @@
class KubeVirtMockHttp(MockHttp):
-
fixtures = ComputeFileFixtures("kubevirt")
def _api_v1_namespaces(self, method, url, body, headers):
@@ -199,7 +197,6 @@
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
def _api_v1_namespaces_default_pods(self, method, url, body, headers):
-
if method == "GET":
body = self.fixtures.load("get_pods.json")
else:
diff --git a/libcloud/test/compute/test_nttcis.py b/libcloud/test/compute/test_nttcis.py
index ff45d08..2a46477 100644
--- a/libcloud/test/compute/test_nttcis.py
+++ b/libcloud/test/compute/test_nttcis.py
@@ -2107,7 +2107,6 @@
class NttCisMockHttp(MockHttp):
-
fixtures = ComputeFileFixtures("nttcis")
def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers):
@@ -3263,7 +3262,6 @@
def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_createPortList(
self, method, url, body, headers
):
-
request = ET.fromstring(body)
if request.tag != "{urn:didata.com:api:cloud:types}" "createPortList":
raise InvalidRequestError(request.tag)
@@ -3290,7 +3288,6 @@
def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_network_editPortList(
self, method, url, body, headers
):
-
request = ET.fromstring(body)
if request.tag != "{urn:didata.com:api:cloud:types}" "editPortList":
raise InvalidRequestError(request.tag)
diff --git a/libcloud/test/compute/test_openstack.py b/libcloud/test/compute/test_openstack.py
index b683249..e8bf332 100644
--- a/libcloud/test/compute/test_openstack.py
+++ b/libcloud/test/compute/test_openstack.py
@@ -722,7 +722,6 @@
return (httplib.NO_CONTENT, "", {}, httplib.responses[httplib.NO_CONTENT])
def _v1_0_slug_shared_ip_groups(self, method, url, body, headers):
-
fixture = (
"v1_slug_shared_ip_group.xml" if method == "POST" else "v1_slug_shared_ip_groups.xml"
)
@@ -1102,7 +1101,6 @@
self.assertEqual(sizes[0].vcpus, 8)
def test_list_sizes_with_specified_pricing(self):
-
pricing = {str(i): i * 5.0 for i in range(1, 9)}
set_pricing(driver_type="compute", driver_name=self.driver.api_name, pricing=pricing)
diff --git a/libcloud/test/compute/test_rackspace.py b/libcloud/test/compute/test_rackspace.py
index 24b0a67..1a05b5a 100644
--- a/libcloud/test/compute/test_rackspace.py
+++ b/libcloud/test/compute/test_rackspace.py
@@ -164,7 +164,6 @@
class RackspaceNovaDfwTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
driver_klass = RackspaceNodeDriver
driver_type = RackspaceNodeDriver
driver_args = RACKSPACE_NOVA_PARAMS
@@ -174,7 +173,6 @@
class RackspaceNovaOrdTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
driver_klass = RackspaceNodeDriver
driver_type = RackspaceNodeDriver
driver_args = RACKSPACE_NOVA_PARAMS
@@ -184,7 +182,6 @@
class RackspaceNovaIadTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
driver_klass = RackspaceNodeDriver
driver_type = RackspaceNodeDriver
driver_args = RACKSPACE_NOVA_PARAMS
@@ -194,7 +191,6 @@
class RackspaceNovaLonTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
driver_klass = RackspaceNodeDriver
driver_type = RackspaceNodeDriver
driver_args = RACKSPACE_NOVA_PARAMS
@@ -207,7 +203,6 @@
class RackspaceNovaSydTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
driver_klass = RackspaceNodeDriver
driver_type = RackspaceNodeDriver
driver_args = RACKSPACE_NOVA_PARAMS
@@ -217,7 +212,6 @@
class RackspaceNovaHkgTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
driver_klass = RackspaceNodeDriver
driver_type = RackspaceNodeDriver
driver_args = RACKSPACE_NOVA_PARAMS
diff --git a/libcloud/test/compute/test_rimuhosting.py b/libcloud/test/compute/test_rimuhosting.py
index 82f1237..3af9fdd 100644
--- a/libcloud/test/compute/test_rimuhosting.py
+++ b/libcloud/test/compute/test_rimuhosting.py
@@ -72,7 +72,6 @@
class RimuHostingMockHttp(MockHttp):
-
fixtures = ComputeFileFixtures("rimuhosting")
def _r_orders(self, method, url, body, headers):
diff --git a/libcloud/test/compute/test_vcloud.py b/libcloud/test/compute/test_vcloud.py
index 3df531e..981f788 100644
--- a/libcloud/test/compute/test_vcloud.py
+++ b/libcloud/test/compute/test_vcloud.py
@@ -636,7 +636,13 @@
def test_change_vm_script_text_and_file_logic(self, _):
assertion_error = False
- for (vm_script_file, vm_script_text, open_succeeds, open_call_count, returned_early,) in (
+ for (
+ vm_script_file,
+ vm_script_text,
+ open_succeeds,
+ open_call_count,
+ returned_early,
+ ) in (
(None, None, True, 0, True),
(None, None, False, 0, True),
(None, "script text", True, 0, False),
@@ -994,7 +1000,6 @@
class TerremarkMockHttp(MockHttp):
-
fixtures = ComputeFileFixtures("terremark")
def _api_v0_8_login(self, method, url, body, headers):
@@ -1072,7 +1077,6 @@
class VCloud_1_5_MockHttp(MockHttp, unittest.TestCase):
-
fixtures = ComputeFileFixtures("vcloud_1_5")
def request(self, method, url, body=None, headers=None, raw=False, stream=False):
diff --git a/libcloud/test/compute/test_vsphere.py b/libcloud/test/compute/test_vsphere.py
index c2593d3..c328a98 100644
--- a/libcloud/test/compute/test_vsphere.py
+++ b/libcloud/test/compute/test_vsphere.py
@@ -22,7 +22,6 @@
class KubeVirtTestCase(unittest.TestCase):
-
driver_cls = VSphere_REST_NodeDriver
fixtures = ComputeFileFixtures("vsphere")
@@ -68,7 +67,6 @@
class VSphereMockHttp(MockHttp):
-
fixtures = ComputeFileFixtures("vsphere")
def _rest_com_vmware_cis_session(self, method, url, body, headers):
diff --git a/libcloud/test/container/test_lxd.py b/libcloud/test/container/test_lxd.py
index 5b5300b..a9a437c 100644
--- a/libcloud/test/container/test_lxd.py
+++ b/libcloud/test/container/test_lxd.py
@@ -201,7 +201,6 @@
)
def _linux_124_containers(self, method, url, body, headers):
-
if method == "GET":
return (
httplib.OK,
@@ -228,7 +227,6 @@
)
def _linux_124_containers_second_lxd_container(self, method, url, body, headers):
-
if method == "PUT" or method == "DELETE":
json = self.fixtures.load("linux_124/background_op.json")
return (httplib.OK, json, {}, httplib.responses[httplib.OK])
@@ -241,7 +239,6 @@
)
def _linux_124_containers_first_lxd_container_state(self, method, url, body, headers):
-
if method == "PUT" or method == "DELETE":
json = self.fixtures.load("linux_124/background_op.json")
return (httplib.OK, json, {}, httplib.responses[httplib.OK])
@@ -250,7 +247,6 @@
return (httplib.OK, json, {}, httplib.responses[httplib.OK])
def _linux_124_containers_second_lxd_container_state(self, method, url, body, headers):
-
if method == "PUT" or method == "DELETE":
json = self.fixtures.load("linux_124/background_op.json")
return (httplib.OK, json, {}, httplib.responses[httplib.OK])
@@ -267,13 +263,11 @@
)
def _linux_124_storage_pools(self, method, url, body, header):
-
if method == "GET":
json = self.fixtures.load("linux_124/storage_pools.json")
return (httplib.OK, json, {}, httplib.responses[httplib.OK])
def _linux_124_storage_pools_pool1(self, method, url, body, header):
-
if method == "GET":
json = self.fixtures.load("linux_124/storage_pool_1.json")
return (httplib.OK, json, {}, httplib.responses[httplib.OK])
@@ -286,7 +280,6 @@
)
def _linux_124_storage_pools_pool2(self, method, url, body, header):
-
if method == "GET":
json = self.fixtures.load("linux_124/storage_pool_2.json")
return (httplib.OK, json, {}, httplib.responses[httplib.OK])
@@ -299,7 +292,6 @@
)
def _linux_124_storage_pools_pool3(self, method, url, body, header):
-
if method == "GET":
json = self.fixtures.load("linux_124/no_meta_pool.json")
return (httplib.OK, json, {}, httplib.responses[httplib.OK])
diff --git a/libcloud/test/dns/test_liquidweb.py b/libcloud/test/dns/test_liquidweb.py
index 1e7e3e4..a0135f1 100644
--- a/libcloud/test/dns/test_liquidweb.py
+++ b/libcloud/test/dns/test_liquidweb.py
@@ -330,7 +330,6 @@
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
def _v1_Network_DNS_Record_update(self, method, url, body, headers):
-
body = self.fixtures.load("update_record.json")
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
diff --git a/libcloud/test/dns/test_luadns.py b/libcloud/test/dns/test_luadns.py
index 97406d2..cc6cb94 100644
--- a/libcloud/test/dns/test_luadns.py
+++ b/libcloud/test/dns/test_luadns.py
@@ -278,7 +278,6 @@
return httplib.OK, body, {}, httplib.responses[httplib.OK]
def _v1_zones_31_GET_RECORD_RECORD_DOES_NOT_EXIST(self, method, url, body, headers):
-
body = self.fixtures.load("get_zone.json")
return httplib.OK, body, {}, httplib.responses[httplib.OK]
diff --git a/libcloud/test/loadbalancer/test_dimensiondata_v2_3.py b/libcloud/test/loadbalancer/test_dimensiondata_v2_3.py
index 7a2b436..5cdc2b2 100644
--- a/libcloud/test/loadbalancer/test_dimensiondata_v2_3.py
+++ b/libcloud/test/loadbalancer/test_dimensiondata_v2_3.py
@@ -490,7 +490,6 @@
class DimensionDataMockHttp(MockHttp):
-
fixtures = LoadBalancerFileFixtures("dimensiondata")
def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers):
diff --git a/libcloud/test/loadbalancer/test_dimensiondata_v2_4.py b/libcloud/test/loadbalancer/test_dimensiondata_v2_4.py
index ab3347a..e8f02cc 100644
--- a/libcloud/test/loadbalancer/test_dimensiondata_v2_4.py
+++ b/libcloud/test/loadbalancer/test_dimensiondata_v2_4.py
@@ -490,7 +490,6 @@
class DimensionDataMockHttp(MockHttp):
-
fixtures = LoadBalancerFileFixtures("dimensiondata")
def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers):
diff --git a/libcloud/test/loadbalancer/test_nttcis.py b/libcloud/test/loadbalancer/test_nttcis.py
index 78b1f01..bdcfc5b 100644
--- a/libcloud/test/loadbalancer/test_nttcis.py
+++ b/libcloud/test/loadbalancer/test_nttcis.py
@@ -628,7 +628,6 @@
class NttCisMockHttp(MockHttp):
-
fixtures = LoadBalancerFileFixtures("nttcis")
def _oec_0_9_myaccount_UNAUTHORIZED(self, method, url, body, headers):
@@ -737,7 +736,6 @@
def _caas_2_7_8a8f6abc_2745_4d8a_9cbc_8dabe5a7d0e4_networkDomainVip_node(
self, method, url, body, headers
):
-
body = self.fixtures.load("networkDomainVip_node.xml")
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
diff --git a/libcloud/test/loadbalancer/test_rackspace.py b/libcloud/test/loadbalancer/test_rackspace.py
index 4bc86fa..cf4923d 100644
--- a/libcloud/test/loadbalancer/test_rackspace.py
+++ b/libcloud/test/loadbalancer/test_rackspace.py
@@ -1344,7 +1344,6 @@
return (httplib.ACCEPTED, "", {}, httplib.responses[httplib.ACCEPTED])
elif method == "POST":
-
json_body = json.loads(body)
access_list = json_body["accessList"]
self.assertEqual("ALLOW", access_list[0]["type"])
diff --git a/libcloud/test/storage/test_azure_blobs.py b/libcloud/test/storage/test_azure_blobs.py
index 1e6d70e..a67e7dd 100644
--- a/libcloud/test/storage/test_azure_blobs.py
+++ b/libcloud/test/storage/test_azure_blobs.py
@@ -44,7 +44,6 @@
class AzureBlobsMockHttp(BaseRangeDownloadMockHttp, unittest.TestCase):
-
fixtures = StorageFileFixtures("azure_blobs")
base_headers = {}
diff --git a/libcloud/test/storage/test_base.py b/libcloud/test/storage/test_base.py
index 41db0c4..e9dc72c 100644
--- a/libcloud/test/storage/test_base.py
+++ b/libcloud/test/storage/test_base.py
@@ -52,7 +52,6 @@
self.driver1.strict_mode = False
def test__upload_object_iterator_must_have_next_method(self):
-
valid_iterators = [BytesIO(b("134")), StringIO("bar")]
invalid_iterators = ["foobar", "", False, True, 1, object()]
diff --git a/libcloud/test/storage/test_cloudfiles.py b/libcloud/test/storage/test_cloudfiles.py
index 2134062..df4a73e 100644
--- a/libcloud/test/storage/test_cloudfiles.py
+++ b/libcloud/test/storage/test_cloudfiles.py
@@ -123,6 +123,14 @@
)
self.driver.connection.cdn_request = False
+ def test_get_endpoint_internalurl(self):
+ self.driver.connection.use_internal_url = True
+ url = (
+ "https://snet-storage101.%s1.clouddrive.com/v1/MossoCloudFS_11111-111111111-1111111111-1111111"
+ % (self.region)
+ )
+ self.assertEqual(url, self.driver.connection.get_endpoint())
+
def test_list_containers(self):
CloudFilesMockHttp.type = "EMPTY"
containers = self.driver.list_containers()
@@ -801,7 +809,6 @@
expected_headers.update(cors_headers)
def intercept_request(request_path, method=None, data=None, headers=None, raw=True):
-
# What we're actually testing
self.assertDictEqual(expected_headers, headers)
@@ -841,7 +848,6 @@
@unittest.skip("Skipping as chunking is disabled in 2.0rc1")
def test_upload_object_via_stream_chunked_encoding(self):
-
# Create enough bytes it should get split into two chunks
bytes_blob = "".join(["\0" for _ in range(CHUNK_SIZE + 1)])
hex_chunk_size = ("%X" % CHUNK_SIZE).encode("utf8")
@@ -1055,7 +1061,6 @@
class CloudFilesMockHttp(BaseRangeDownloadMockHttp, unittest.TestCase):
-
fixtures = StorageFileFixtures("cloudfiles")
base_headers = {"content-type": "application/json; charset=UTF-8"}
@@ -1255,7 +1260,6 @@
return (status_code, body, headers, httplib.responses[httplib.OK])
def _v1_MossoCloudFS_foo_bar_container_object_PURGE_SUCCESS(self, method, url, body, headers):
-
if method == "DELETE":
# test_ex_purge_from_cdn
headers = self.base_headers
@@ -1265,7 +1269,6 @@
def _v1_MossoCloudFS_foo_bar_container_object_PURGE_SUCCESS_EMAIL(
self, method, url, body, headers
):
-
if method == "DELETE":
# test_ex_purge_from_cdn_with_email
self.assertEqual(headers["X-Purge-Email"], "test@test.com")
@@ -1274,7 +1277,6 @@
return (status_code, body, headers, httplib.responses[httplib.OK])
def _v1_MossoCloudFS_foo_bar_container_NOT_FOUND(self, method, url, body, headers):
-
if method == "DELETE":
# test_delete_container_not_found
body = self.fixtures.load("list_container_objects_empty.json")
@@ -1283,7 +1285,6 @@
return (status_code, body, headers, httplib.responses[httplib.OK])
def _v1_MossoCloudFS_foo_bar_container_NOT_EMPTY(self, method, url, body, headers):
-
if method == "DELETE":
# test_delete_container_not_empty
body = self.fixtures.load("list_container_objects_empty.json")
@@ -1292,7 +1293,6 @@
return (status_code, body, headers, httplib.responses[httplib.OK])
def _v1_MossoCloudFS_foo_bar_container_foo_bar_object(self, method, url, body, headers):
-
if method == "DELETE":
# test_delete_object_success
body = self.fixtures.load("list_container_objects_empty.json")
@@ -1398,7 +1398,6 @@
def _v1_MossoCloudFS_foo_bar_container_foo_test_stream_data_seek(
self, method, url, body, headers
):
-
# test_upload_object_via_stream_stream_seek_at_end
hasher = hashlib.md5()
hasher.update(b"123456789")
diff --git a/libcloud/test/storage/test_oss.py b/libcloud/test/storage/test_oss.py
index 66394d4..3debf9d 100644
--- a/libcloud/test/storage/test_oss.py
+++ b/libcloud/test/storage/test_oss.py
@@ -76,7 +76,6 @@
class OSSMockHttp(MockHttp, unittest.TestCase):
-
fixtures = StorageFileFixtures("oss")
base_headers = {}
diff --git a/libcloud/test/storage/test_s3.py b/libcloud/test/storage/test_s3.py
index e5ea383..46aa60a 100644
--- a/libcloud/test/storage/test_s3.py
+++ b/libcloud/test/storage/test_s3.py
@@ -51,7 +51,6 @@
class S3MockHttp(BaseRangeDownloadMockHttp, unittest.TestCase):
-
fixtures = StorageFileFixtures("s3")
base_headers = {}
@@ -1088,6 +1087,28 @@
self.assertEqual(obj.name, object_name)
self.assertEqual(obj.size, 3)
+ def test_upload_small_object_with_glacier_ir(self):
+ if self.driver.supports_s3_multipart_upload:
+ self.mock_response_klass.type = "MULTIPART"
+ else:
+ self.mock_response_klass.type = None
+
+ container = Container(name="foo_bar_container", extra={}, driver=self.driver)
+ object_name = "foo_test_stream_data"
+ storage_class = "glacier_ir"
+ iterator = BytesIO(b("234"))
+ extra = {"content_type": "text/plain"}
+ obj = self.driver.upload_object_via_stream(
+ container=container,
+ object_name=object_name,
+ iterator=iterator,
+ extra=extra,
+ ex_storage_class=storage_class,
+ )
+
+ self.assertEqual(obj.name, object_name)
+ self.assertEqual(obj.size, 3)
+
def test_upload_big_object_via_stream(self):
if self.driver.supports_s3_multipart_upload:
self.mock_response_klass.type = "MULTIPART"
diff --git a/libcloud/test/test_utils.py b/libcloud/test/test_utils.py
index 69d3705..49a4805 100644
--- a/libcloud/test/test_utils.py
+++ b/libcloud/test/test_utils.py
@@ -479,7 +479,6 @@
class TestPublicKeyUtils(unittest.TestCase):
-
PUBKEY = (
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDOfbWSXOlqvYjZmRO84/lIoV4gvuX+"
"P1lLg50MMg6jZjLZIlYY081XPRmuom0xY0+BO++J2KgLl7gxJ6xMsKK2VQ+TakdfAH20"
diff --git a/libcloud/utils/decorators.py b/libcloud/utils/decorators.py
index 847933f..1538e32 100644
--- a/libcloud/utils/decorators.py
+++ b/libcloud/utils/decorators.py
@@ -34,7 +34,6 @@
try:
return func(*args, **kwargs)
except Exception as e:
-
if isinstance(e, LibcloudError):
raise e
diff --git a/mypy.ini b/mypy.ini
deleted file mode 100644
index bc5ffe3..0000000
--- a/mypy.ini
+++ /dev/null
@@ -1,46 +0,0 @@
-[mypy]
-python_version = 3.7
-platform = linux
-show_error_context = True
-show_column_numbers = True
-# This Package contains generated Protobuf files
-#mypy_path = ../common/:common/
-
-# List of ignore files for packages and libraries which don't have type hints
-[mypy-lxml.*]
-ignore_missing_imports = True
-
-[mypy-xml.dom.*]
-ignore_missing_imports = True
-
-[mypy-xmlrpc.*]
-ignore_missing_imports = True
-
-[mypy-paramiko.*]
-ignore_missing_imports = True
-
-[mypy-cryptography.*]
-ignore_missing_imports = True
-
-[mypy-lockfile.*]
-ignore_missing_imports = True
-
-# Ignored local modules
-[mypy-libcloud.utils.py3]
-ignore_errors = True
-
-# NOTE: Fixing drivers will take a while
-[mypy-libcloud.compute.drivers.*]
-ignore_errors = True
-
-# NOTE: Fixing drivers will take a while
-[mypy-libcloud.storage.drivers.*]
-ignore_errors = True
-
-# NOTE: Fixing drivers will take a while
-[mypy-libcloud.dns.drivers.*]
-ignore_errors = True
-
-# NOTE: Fixing drivers will take a while
-[mypy-libcloud.container.drivers.*]
-ignore_errors = True
diff --git a/pyproject.toml b/pyproject.toml
index 7a2fe8b..6c510ca 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,17 +1,22 @@
+[build-system]
+requires = ["setuptools~=66.1", "wheel~=0.37.1"]
+build-backend = "setuptools.build_meta"
+
[tool.black]
line_length = 100
target_version = ['py37', 'py38', 'py39', 'py310']
include = '\.pyi?$'
extended_exclude = '''
(
- /(
- | \.git
- | \.virtualenv
- | __pycache__
- )/
+ /(
+ | \.git
+ | \.virtualenv
+ | __pycache__
+ )/
)
'''
+
[tool.isort]
profile = "black"
multi_line_output = 3
@@ -19,3 +24,96 @@
src_paths = ["libcloud", "contrib", "docs", "demos", "pylint_plugins", "integration"]
skip_glob = [".venv/*", ".tox/*", ".github/actions/*"]
length_sort = true
+
+
+[tool.pytest.ini_options]
+# Set options for pytest
+python_classes = "*Test"
+testpaths = "libcloud/test"
+# Show slowest 10 tests in the output
+addopts = "--durations=10"
+# Ignore UserWarning's
+filterwarnings = ["ignore::UserWarning"]
+
+
+[tool.bandit]
+exclude_dirs = [".tox", ".git", "build", "dist", "venv", "tests/*"]
+skips = ["B411"]
+
+
+[tool.pylint.MASTER]
+ignore = "test,constants"
+persistent = "yes"
+load-plugins = ""
+
+[tool.pylint.'MESSAGES CONTROL']
+disable = "redefined-builtin,too-many-arguments,too-few-public-methods,missing-docstring,invalid-name,abstract-method"
+
+[tool.pylint.TYPECHECK]
+generated-members = "async_request,objects"
+
+[tool.pylint.VARIABLES]
+init-import = "no"
+dummy-variables-rgx = "_|dummy"
+additional-builtins = ""
+
+[tool.pylint.FORMAT]
+max-line-length = 100
+max-module-lines = 1000
+indent-string = " "
+
+
+[tool.mypy]
+python_version = 3.7
+platform = "linux"
+show_error_context = true
+show_column_numbers = true
+
+[[tool.mypy.overrides]]
+module = [
+ "lxml",
+ "xml.dom",
+ "xmlrpc.*",
+ "paramiko.*",
+ "cryptography.*",
+ "lockfile.*",
+]
+ignore_missing_imports = true
+
+[[tool.mypy.overrides]]
+module = [
+ "libcloud.utils.py3",
+ "libcloud.compute.drivers.*",
+ "libcloud.storage.drivers.*",
+ "libcloud.dns.drivers.*",
+ "libcloud.container.drivers.*",
+]
+ignore_errors = true
+
+[tool.coverage.run]
+branch = true
+source = ["libcloud"]
+
+[tool.coverage.report]
+exclude_lines = [
+ # Have to re-enable the standard pragma
+ "pragma: no cover",
+ # Don't complain about missing debug-only code:
+ "def __repr__",
+ "def __str__",
+ "if self\\.debug",
+ # Don't complain if tests don't hit defensive assertion code:
+ "raise AssertionError",
+ "raise NotImplementedError",
+ # Don't complain if non-runnable code isn't run:
+ "if 0:",
+ "if __name__ == .__main__.:",
+ "__all__",
+ "import",
+ "deprecated_warning",
+ "in_development_warning",
+]
+ignore_errors = true
+
+[tool.coverage.html]
+directory = "coverage_html_report"
diff --git a/pytest.ini b/pytest.ini
deleted file mode 100644
index cdecf53..0000000
--- a/pytest.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[pytest]
-python_classes=*Test
-testpaths=libcloud/test
-# Show slowest 10 tests in the output
-addopts = --durations=10
-# Ignore UserWarning's
-filterwarnings =
- ignore::UserWarning
diff --git a/requirements-docs.txt b/requirements-docs.txt
index 01227da..7b7ec59 100644
--- a/requirements-docs.txt
+++ b/requirements-docs.txt
@@ -1,3 +1,3 @@
-rstcheck==6.1.1; python_version >= '3.7'
+rstcheck==6.1.2; python_version >= '3.7'
fasteners
sphinx==6.1.3
diff --git a/requirements-lint.txt b/requirements-lint.txt
index 8cd7452..b018032 100644
--- a/requirements-lint.txt
+++ b/requirements-lint.txt
@@ -1,12 +1,12 @@
pep8==1.7.1
flake8==5.0.4
-astroid==2.13.3; python_version >= '3.8'
-pylint==2.15.10; python_version >= '3.8'
-bandit==1.7.4; python_version >= '3.7'
-black==22.12.0; python_version >= '3.6' and implementation_name == "cpython"
+astroid==2.15.6; python_version >= '3.8'
+pylint==2.17.5; python_version >= '3.8'
+bandit[toml]==1.7.4; python_version >= '3.7'
+black==23.7.0; python_version >= '3.7' and implementation_name == "cpython"
isort[pyproject]==5.12.0; python_version >= '3.8'
pyupgrade==3.3.1
-rstcheck==6.1.1; python_version >= '3.7'
+rstcheck==6.1.2; python_version >= '3.7'
requests>=2.27.1
-paramiko==3.0.0; platform_python_implementation != 'PyPy'
+paramiko==3.3.1; platform_python_implementation != 'PyPy'
diff --git a/requirements-mypy.txt b/requirements-mypy.txt
index ab556f4..9ca1dcc 100644
--- a/requirements-mypy.txt
+++ b/requirements-mypy.txt
@@ -1,6 +1,6 @@
typing
# Mypy requires typed-ast, which is broken on PyPy 3.7 (could work in PyPy 3.8).
-mypy==0.982; implementation_name == "cpython"
+mypy==1.4.1; implementation_name == "cpython"
types-simplejson
types-certifi
types-requests
diff --git a/requirements-tests.txt b/requirements-tests.txt
index e9e8c07..9f1d56a 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -1,19 +1,18 @@
-codecov==2.1.12
-coverage==7.1.0; python_version >= '3.8'
-requests>=2.27.1
-requests_mock==1.10.0
-pytest==7.2.1
-pytest-xdist==3.1.0
+coverage[toml]==7.2.7; python_version >= '3.8'
+requests>=2.31.0
+requests_mock==1.11.0
+pytest==7.4.0
+pytest-xdist==3.3.1
pytest-timeout==2.1.0
pytest-benchmark[histogram]==4.0.0
-cryptography==39.0.0
+cryptography==41.0.2
# NOTE: Only needed by nttcis loadbalancer driver
-pyopenssl==23.0.0
+pyopenssl==23.2.0
more-itertools==9.0.0
# Required by subset of tests
fasteners
-paramiko==3.0.0; platform_python_implementation != 'PyPy'
+paramiko==3.3.1; platform_python_implementation != 'PyPy'
libvirt-python==9.0.0
diff --git a/setup.py b/setup.py
index cd96eaa..10b3d46 100644
--- a/setup.py
+++ b/setup.py
@@ -321,6 +321,7 @@
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
],
diff --git a/tox.ini b/tox.ini
index efdf9ec..4d3affb 100644
--- a/tox.ini
+++ b/tox.ini
@@ -19,6 +19,7 @@
/bin/bash
scripts/*.sh
basepython =
+ py3.12-dev: python3.12
pypypy3: pypy3
pypypy3.7: pypy3.7
pypypy-3.7: pypy3.7
@@ -38,7 +39,7 @@
# python setup.py test
# for pytest-xdist, we want to distribute tests by file aka --dist loadfile
commands = cp libcloud/test/secrets.py-dist libcloud/test/secrets.py
- pytest -rsx -vvv --capture=tee-sys -o log_cli=True --durations=10 --timeout=15 -n auto --dist loadfile --ignore libcloud/test/benchmarks/ --ignore-glob "*test_list_objects_filtering_performance*"
+ pytest --color=yes -rsx -vvv --capture=tee-sys -o log_cli=True --durations=10 --timeout=15 -n auto --dist loadfile --ignore libcloud/test/benchmarks/ --ignore-glob "*test_list_objects_filtering_performance*"
[testenv:py3.6-dist]
# Verify library installs without any dependencies when using python setup.py
@@ -235,16 +236,16 @@
PYTHONPATH={toxinidir}
deps =
-r{toxinidir}/requirements-lint.txt
-commands = pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc libcloud/common/
- pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc libcloud/compute/
- pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc libcloud/container/
- pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc libcloud/backup/
- pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc libcloud/dns/
- pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc libcloud/storage/
- pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc libcloud/utils/
- pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc demos/
- pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc contrib/
- pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./.pylintrc pylint_plugins/
+commands = pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml libcloud/common/
+ pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml libcloud/compute/
+ pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml libcloud/container/
+ pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml libcloud/backup/
+ pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml libcloud/dns/
+ pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml libcloud/storage/
+ pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml libcloud/utils/
+ pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml demos/
+ pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml contrib/
+ pylint -E --load-plugins=pylint_plugins.driver_class --rcfile=./pyproject.toml pylint_plugins/
[testenv:lint]
deps =
@@ -264,7 +265,7 @@
[testenv:bandit]
deps =
-r{toxinidir}/requirements-lint.txt
-commands = bandit --configfile .bandit.yaml -lll -r libcloud/
+commands = bandit --configfile pyproject.toml -lll -r libcloud/
[testenv:black]
deps =
@@ -319,7 +320,7 @@
deps =
-r{toxinidir}/requirements-tests.txt
-r{toxinidir}/integration/storage/requirements.txt
-commands = pytest -rsx -vvv --capture=tee-sys -o log_cli=True --durations=10 integration/storage
+commands = pytest --color=yes -rsx -vvv --capture=tee-sys -o log_cli=True --durations=10 integration/storage
[testenv:coverage]
deps =
@@ -341,7 +342,7 @@
CRYPTOGRAPHY_ALLOW_OPENSSL_102=1
commands = cp libcloud/test/secrets.py-dist libcloud/test/secrets.py
coverage run --source=libcloud setup.py test
- codecov
+ coverage xml
[testenv:isort]
deps =
@@ -386,8 +387,8 @@
[testenv:micro-benchmarks]
commands =
cp libcloud/test/secrets.py-dist libcloud/test/secrets.py
- pytest -s -v --timeout 60 --benchmark-only --benchmark-name=short --benchmark-columns=min,max,mean,stddev,median,ops,rounds --benchmark-histogram=benchmark_histograms/benchmark --benchmark-group-by=group,param:sort_objects libcloud/test/benchmarks/test_list_objects_filtering_performance.py
- pytest -s -v --timeout 60 --benchmark-only --benchmark-name=short --benchmark-columns=min,max,mean,stddev,median,ops,rounds --benchmark-histogram=benchmark_histograms/benchmark --benchmark-group-by=group,func,param:read_in_chunks_func libcloud/test/benchmarks/test_read_in_chunks.py
+ pytest --color=yes -s -v --timeout 60 --benchmark-only --benchmark-name=short --benchmark-columns=min,max,mean,stddev,median,ops,rounds --benchmark-histogram=benchmark_histograms/benchmark --benchmark-group-by=group,param:sort_objects libcloud/test/benchmarks/test_list_objects_filtering_performance.py
+ pytest --color=yes -s -v --timeout 60 --benchmark-only --benchmark-name=short --benchmark-columns=min,max,mean,stddev,median,ops,rounds --benchmark-histogram=benchmark_histograms/benchmark --benchmark-group-by=group,func,param:read_in_chunks_func libcloud/test/benchmarks/test_read_in_chunks.py
[testenv:import-timings]
setenv =