Repository: apache/libcloud (language: python)

Issue:
Update Cloud Files and Load Balancer Rackspace Connection Classes to pass on kwargs
WHY

Rackspace is currently rolling out Auth 2.0.  The existing libcloud connection classes for Load Balancers and Cloud Files do not pass on kwargs to their superclass, essentially forcing these drivers to always use Auth 1.0/Auth 1.1 (whatever their particular defaults are).

The OpenStack Nova Driver does not define a constructor so we get this behavior for free there.

WHAT

Just pass on any kwargs that are passed into the superclass.

Tests pass.  Let me know if you'd like me to write some tests around this specific change.  When Load Balancers are in the Auth 2.0 service catalog we will aim at a more complete patch.  (Would we prefer extra connection classes for CloudFiles_Auth_2_0 in this situation?)



Discussion / hints:
Merged in 1213945.

thanks!


Fix patch:
diff --git a/.asf.yaml b/.asf.yaml
index ddd6804af8..487c3d7048 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -35,6 +35,8 @@ github:
     squash: true
     merge: true
     rebase: false
+  autolink_jira:
+    - LIBCLOUD
   protected_branches:
     trunk:
       required_status_checks:
@@ -46,6 +48,7 @@ github:
           - "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 80ddbf0ab6..0000000000
--- 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 925a7a72e8..61caf6f465 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 61014db9a3..0000000000
--- 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 0000000000..f931fc5ed3
--- /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 0000000000..ff27519a16
--- /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 0000000000..c83f9139af
--- /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/README.md b/.github/actions/gh-action-pip-audit/README.md
index c7f790d3b9..ff434acf5b 100644
--- a/.github/actions/gh-action-pip-audit/README.md
+++ b/.github/actions/gh-action-pip-audit/README.md
@@ -32,7 +32,7 @@ jobs:
       - 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 @@ jobs:
           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 @@ The `inputs` setting controls what sources `pip-audit` runs on.
 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 one or more requirements-style inputs:
 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 @@ Example: use the virtual environment specified at `env/`, relative to the
 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 @@ installed directly into the current environment are included.
 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 @@ It's directly equivalent to `pip-audit --vulnerability-service=...`.
 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 @@ It's directly equivalent to `pip-audit --require-hashes ...`.
 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 @@ It's directly equivalent to `pip-audit --no-deps ...`.
 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 @@ is rendered at the end of the action.
 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 @@ indices to search (such as a corporate index with private packages), see
 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 @@ indexes to search when resolving dependencies. Each URL is whitespace-separated.
 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 @@ ignore (i.e., exclude from the results) if present. Each ID is whitespace-separa
 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
   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-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.
+The `internal-be-careful-extra-flags` setting passes the specified flags
+to `pip-audit`.
 
-  Be mindful that `pip-audit`'s own debug logs contain HTTP requests,
-  which may or may not be sensitive in your use case.
-
-  Example:
+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 @@ If you're auditing a requirements file, consider setting `no-deps: true` or
 `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 @@ If you're auditing a requirements file, consider setting `no-deps: true` or
 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 @@ by the host system itself, or other Python projects that happen to be installed.
 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 @@ and, more aggressively, specify that only dependencies marked as "local"
 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 @@ jobs:
         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 75d8d7ffcd..dd624adbd6 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 _summary(msg):
 
 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 @@ def _fatal_help(msg):
     "--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 @@ def _fatal_help(msg):
 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 3574e61fae..39e9d3d940 100644
--- a/.github/actions/gh-action-pip-audit/action.yml
+++ b/.github/actions/gh-action-pip-audit/action.yml
@@ -46,10 +46,10 @@ inputs:
     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 @@ runs:
         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 931128f8f1..546e8fe026 100644
--- a/.github/actions/gh-action-pip-audit/requirements.txt
+++ b/.github/actions/gh-action-pip-audit/requirements.txt
@@ -1,1 +1,1 @@
-pip-audit ~= 2.0, >= 2.4.13
+pip-audit ~= 2.0, >= 2.5.6
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 4941da400a..7868071483 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -3,9 +3,11 @@ updates:
   - 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/main.yml b/.github/workflows/main.yml
index 9d881eb643..cf03c62dda 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -14,6 +14,11 @@ permissions:
   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 @@ jobs:
           - 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 @@ jobs:
 
       - 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 @@ jobs:
 
       - 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 @@ jobs:
 
       - 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 @@ jobs:
 
       - 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 @@ jobs:
           # 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 @@ jobs:
 
       - name: Run Bandit Check
         run: |
-          script -e -c "tox -e bandit"
+          tox -e bandit
 
   micro-benchmarks:
     name: Micro Benchmarks
@@ -344,7 +358,7 @@ jobs:
 
       - 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 @@ jobs:
 
       - 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 a0b4ddde06..0000000000
--- 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 9668cf036d..346a627893 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/container/__init__.py
 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 cce0e66208..13a0722d5f 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -7,13 +7,22 @@ Changes in Apache Libcloud in development
 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,26 @@ Storage
   (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]
+
+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 cc4af03bb5..a8ddee371d 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,7 +4,7 @@ include example_*.py
 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 520fe30a39..201c2263da 100755
--- a/contrib/generate_contributor_list.py
+++ b/contrib/generate_contributor_list.py
@@ -106,7 +106,6 @@ def parse_changes_file(file_path, versions=None):
 
 
 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 53ee06b2a4..7c33ef55b8 100755
--- a/contrib/scrape-azure-prices.py
+++ b/contrib/scrape-azure-prices.py
@@ -40,7 +40,6 @@ def get_azure_prices():
     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 6a029ea87f..a4b6f5a37f 100755
--- a/contrib/scrape-ec2-prices.py
+++ b/contrib/scrape-ec2-prices.py
@@ -305,7 +305,7 @@ def sort_key_by_numeric_other(key_value):
     """
     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 6621e47b68..c8ae02342e 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 f40cdf4432..c121c6ba7f 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 e663a2eeb9..ef255a28fa 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 3a84bf4967..4ed5f39a49 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 9c05ce5790..353ae00c8a 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 cd296e8c34..168a30fdfb 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 b05b9d6fab..39da462b90 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 7b8d1bf80c..55932af6d6 100644
--- a/docs/examples/container/lxd/example_lxd.py
+++ b/docs/examples/container/lxd/example_lxd.py
@@ -123,7 +123,6 @@ def work_with_containers():
 
 
 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 f7d0f1ecd4..4ea775067b 100644
--- a/libcloud/backup/drivers/dimensiondata.py
+++ b/libcloud/backup/drivers/dimensiondata.py
@@ -63,7 +63,6 @@ def __init__(
         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 84ff648130..2414432df4 100644
--- a/libcloud/common/aliyun.py
+++ b/libcloud/common/aliyun.py
@@ -167,7 +167,6 @@ class AliyunConnection(ConnectionUserAndKey):
 
 
 class SignedAliyunConnection(AliyunConnection):
-
     api_version = None
 
     def __init__(
diff --git a/libcloud/common/azure.py b/libcloud/common/azure.py
index 99cff66273..cce42df901 100644
--- a/libcloud/common/azure.py
+++ b/libcloud/common/azure.py
@@ -191,7 +191,6 @@ def request(
         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 8f849c15b9..b8caf3a2bd 100644
--- a/libcloud/common/azure_arm.py
+++ b/libcloud/common/azure_arm.py
@@ -209,7 +209,6 @@ def connect(self, **kwargs):
         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 ff6b74ac67..1516409983 100644
--- a/libcloud/common/durabledns.py
+++ b/libcloud/common/durabledns.py
@@ -160,7 +160,6 @@ def __repr__(self):
 
 
 class DurableResponse(XmlResponse):
-
     errors = []  # type: List[Dict]
     objects = []  # type: List[Dict]
 
diff --git a/libcloud/common/google.py b/libcloud/common/google.py
index aa79859dbe..1869e2e1d9 100644
--- a/libcloud/common/google.py
+++ b/libcloud/common/google.py
@@ -499,7 +499,6 @@ def _receive_code_through_local_loopback(self):
         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 5582221243..1c808f5cf8 100644
--- a/libcloud/common/gridscale.py
+++ b/libcloud/common/gridscale.py
@@ -96,7 +96,6 @@ def _poll_request_initial(self, **kwargs):
         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 465af7df23..f4fadf68a2 100644
--- a/libcloud/common/kubernetes.py
+++ b/libcloud/common/kubernetes.py
@@ -62,7 +62,6 @@ def __repr__(self):
 
 
 class KubernetesResponse(JsonResponse):
-
     valid_response_codes = [
         httplib.OK,
         httplib.ACCEPTED,
@@ -93,7 +92,6 @@ def __init__(
         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 9519b8c25f..5d36dfad60 100644
--- a/libcloud/common/nttcis.py
+++ b/libcloud/common/nttcis.py
@@ -2293,7 +2293,6 @@ def __init__(self, parent_element):
                 # 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/types.py b/libcloud/common/types.py
index c5b1732cfb..673e0d9d75 100644
--- a/libcloud/common/types.py
+++ b/libcloud/common/types.py
@@ -89,7 +89,7 @@ class LibcloudError(Exception):
     """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 10f86dc7d9..0415715217 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 @@ class VultrResponse(JsonResponse):
     }
 
     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 @@ def _make_excp(self, error):
         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 278fc404d4..e22d913726 100644
--- a/libcloud/common/xmlrpc.py
+++ b/libcloud/common/xmlrpc.py
@@ -53,7 +53,6 @@ def raise_exception_for_error(self, error_code, message):
 
 
 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 ac22a2d3c6..7ec7772c17 100644
--- a/libcloud/compute/base.py
+++ b/libcloud/compute/base.py
@@ -118,8 +118,8 @@ class UuidMixin:
     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 @@ def __init__(
         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 @@ def __init__(
         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 @@ def __init__(
         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 @@ def create_node(
         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 @@ def deploy_node(
         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 364e0c7d90..b5c29a18fa 100644
--- a/libcloud/compute/drivers/azure.py
+++ b/libcloud/compute/drivers/azure.py
@@ -664,7 +664,6 @@ def create_node(
             )
 
             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 @@ def ex_add_instance_endpoints(self, node, endpoints, ex_deployment_slot="Product
         return result
 
     def ex_set_instance_endpoints(self, node, endpoints, ex_deployment_slot="Production"):
-
         """
         For example::
 
@@ -1895,7 +1893,6 @@ def create_storage_service_to_xml(
         affinity_group,
         extended_properties=None,
     ):
-
         return AzureXmlSerializer.doc_from_data(
             "CreateStorageServiceInput",
             [
@@ -2249,7 +2246,6 @@ def network_configuration_to_xml(configuration, xml):
                 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 @@ def role_to_xml(
         system_configuration_set,
         xml,
     ):
-
         AzureXmlSerializer.data_to_xml([("RoleName", role_name)], xml)
         AzureXmlSerializer.data_to_xml([("RoleType", role_type)], xml)
 
@@ -2396,7 +2391,6 @@ def update_role_to_xml(
         vm_image_name,
         role_size,
     ):
-
         doc = AzureXmlSerializer.doc_from_xml("PersistentVMRole")
         AzureXmlSerializer.role_to_xml(
             availability_set_name,
@@ -2459,7 +2453,6 @@ def virtual_machine_deployment_to_xml(
         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 @@ def doc_from_data(document_element_name, data, extended_properties=None):
 
     @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 WindowsAzureData:
 
 
 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 971c2152bb..224b831b11 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 @@ def list_nodes(self, ex_resource_group=None, ex_fetch_nic=True, ex_fetch_power_s
 
         :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 @@ def list_nodes(self, ex_resource_group=None, ex_fetch_nic=True, ex_fetch_power_s
             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 e6c6b345ff..b92895df74 100644
--- a/libcloud/compute/drivers/cloudstack.py
+++ b/libcloud/compute/drivers/cloudstack.py
@@ -44,7 +44,6 @@ def transform_int_or_unlimited(value):
     try:
         return int(value)
     except ValueError as e:
-
         if str(value).lower() == "unlimited":
             return -1
 
@@ -467,7 +466,6 @@ def __init__(
         start_port=None,
         end_port=None,
     ):
-
         """
         A Firewall rule.
 
@@ -530,7 +528,6 @@ def __init__(
         start_port=None,
         end_port=None,
     ):
-
         """
         A egress firewall rule.
 
@@ -1383,7 +1380,6 @@ def list_images(self, location=None):
         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 @@ def ex_list_vpcs(self, project=None):
 
         networks = []
         for vpc in vpcs:
-
             networks.append(
                 CloudStackVPC(
                     vpc["name"],
@@ -2146,7 +2141,6 @@ def ex_list_routers(self, vpc_id=None):
 
         routers = []
         for router in rts:
-
             routers.append(
                 CloudStackRouter(
                     router["id"],
@@ -4206,7 +4200,6 @@ def ex_attach_nic_to_node(self, node, network, ip_address=None):
         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 dca4b18f5d..1d0148a890 100644
--- a/libcloud/compute/drivers/dimensiondata.py
+++ b/libcloud/compute/drivers/dimensiondata.py
@@ -120,7 +120,6 @@ def __init__(
         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 @@ def ex_modify_tag_key(
         value_required=None,
         display_on_report=None,
     ):
-
         """
         Modify a specific tag key
 
@@ -3720,7 +3718,6 @@ def ex_create_node_uncustomized(
         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 9a3e2eabaa..506e6f6cb4 100644
--- a/libcloud/compute/drivers/ec2.py
+++ b/libcloud/compute/drivers/ec2.py
@@ -3048,7 +3048,6 @@ def ex_authorize_security_group_permissive(self, name):
         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 @@ def ex_describe_addresses(self, nodes):
         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_images(self, object):
         ]
 
     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 @@ def _to_image(self, element):
             xpath="billingProducts/item/billingProduct",
             namespace=NAMESPACE,
         ):
-
             billing_products.append(p.text)
 
         # Get our tags
@@ -4764,7 +4760,6 @@ def _to_interface(self, element, name=None):
         for item in findall(
             element=element, xpath="privateIpAddressesSet/item", namespace=NAMESPACE
         ):
-
             priv_ips.append(
                 {
                     "private_ip": findtext(
@@ -5968,7 +5963,6 @@ def ex_describe_quotas(self, dry_run=False, filters=None, max_results=None, mark
         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 @@ def ex_get_product_type(self, image_id, snapshot_id=None):
         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 @@ def ex_describe_product_types(self, filters=None):
         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 c8a140af58..49b50c207d 100644
--- a/libcloud/compute/drivers/gce.py
+++ b/libcloud/compute/drivers/gce.py
@@ -496,7 +496,6 @@ def __init__(
         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 479ea0b445..c68c482f6a 100644
--- a/libcloud/compute/drivers/gridscale.py
+++ b/libcloud/compute/drivers/gridscale.py
@@ -650,7 +650,6 @@ def reboot_node(self, node, ex_sleep_interval=3):
             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 b668f8e3e3..32cc424394 100644
--- a/libcloud/compute/drivers/internetsolutions.py
+++ b/libcloud/compute/drivers/internetsolutions.py
@@ -47,7 +47,6 @@ def __init__(
         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 e5f8b4afeb..a76293d9d7 100644
--- a/libcloud/compute/drivers/kubevirt.py
+++ b/libcloud/compute/drivers/kubevirt.py
@@ -438,7 +438,6 @@ def create_node(
         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 @@ def list_locations(self):
         return namespaces
 
     def list_sizes(self, location=None):
-
         namespace = ""
         if location:
             namespace = location.name
@@ -678,7 +676,6 @@ def _create_volume_dynamic(
             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 @@ def detach_volume(self, volume, ex_node):
             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 @@ def ex_list_persistent_volume_claims(self, namespace="default"):
         return pvcs
 
     def ex_list_storage_classes(self):
-
         # sc = storage class
         sc_req = "/apis/storage.k8s.io/v1/storageclasses"
         try:
@@ -940,7 +935,6 @@ def _to_node(self, vm, is_stopped=False):
             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 2df7000aca..50f2fefdde 100644
--- a/libcloud/compute/drivers/linode.py
+++ b/libcloud/compute/drivers/linode.py
@@ -799,7 +799,6 @@ def _to_nodes(self, objs):
 
 
 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 04de2cc712..f47d2fc113 100644
--- a/libcloud/compute/drivers/ntta.py
+++ b/libcloud/compute/drivers/ntta.py
@@ -47,7 +47,6 @@ def __init__(
         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 040e468495..a0d82868b8 100644
--- a/libcloud/compute/drivers/nttcis.py
+++ b/libcloud/compute/drivers/nttcis.py
@@ -123,7 +123,6 @@ def __init__(
         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 @@ def ex_modify_tag_key(
         value_required=None,
         display_on_report=None,
     ):
-
         """
         Modify a specific tag key
 
@@ -4282,7 +4280,6 @@ def ex_create_node_uncustomized(
         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 8b7b7377fd..ea8eb76ba7 100644
--- a/libcloud/compute/drivers/outscale.py
+++ b/libcloud/compute/drivers/outscale.py
@@ -7743,22 +7743,25 @@ def _to_volume(self, volume):
         )
 
     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 692248a988..3c4e45738d 100644
--- a/libcloud/compute/drivers/vsphere.py
+++ b/libcloud/compute/drivers/vsphere.py
@@ -1200,7 +1200,6 @@ class VSphere_REST_NodeDriver(NodeDriver):
     ]
 
     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 @@ def ex_list_hosts(
         ex_filter_datacenters=None,
         ex_filter_connection_states=None,
     ):
-
         kwargs = {
             "filter.folders": ex_filter_folders,
             "filter.names": ex_filter_names,
@@ -1782,7 +1780,6 @@ def list_images(self, **kwargs):
         return images
 
     def ex_list_networks(self):
-
         request = "/rest/vcenter/network"
         response = self._request(request).object["value"]
         networks = []
@@ -1950,7 +1947,6 @@ def create_node(
             )
 
         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 1ec7148ed0..b684a6d4ee 100644
--- a/libcloud/container/base.py
+++ b/libcloud/container/base.py
@@ -41,8 +41,8 @@ def __init__(
         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 @@ def __init__(
         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 @@ def __init__(
         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 a202c4eec1..4f64176363 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 @@ def __repr__(self):
 
 
 class DockerConnection(ConnectionUserAndKey):
-
     responseCls = DockerResponse
     timeout = 60
 
@@ -120,7 +118,6 @@ def add_default_headers(self, headers):
 
 
 class DockertlsConnection(KeyCertificateConnection):
-
     responseCls = DockerResponse
 
     def __init__(
@@ -134,7 +131,6 @@ def __init__(
         cert_file="",
         **kwargs,
     ):
-
         super().__init__(
             key_file=key_file,
             cert_file=cert_file,
@@ -167,7 +163,6 @@ def __init__(
             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 3841d3155a..46e3c3353e 100644
--- a/libcloud/container/drivers/lxd.py
+++ b/libcloud/container/drivers/lxd.py
@@ -158,7 +158,6 @@ class LXDStoragePool:
     """
 
     def __init__(self, name, driver, used_by, config, managed):
-
         # the name of the storage pool
         self.name = name
 
@@ -216,7 +215,6 @@ class LXDServerInfo:
 
     @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 @@ def build_from_response(cls, metadata):
         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 @@ class LXDResponse(JsonResponse):
     ]
 
     def parse_body(self):
-
         if len(self.body) == 0 and not self.parse_zero_length_body:
             return self.body
 
@@ -334,7 +330,6 @@ def add_default_headers(self, headers):
 
 
 class LXDtlsConnection(KeyCertificateConnection):
-
     responseCls = LXDResponse
 
     def __init__(
@@ -350,7 +345,6 @@ def __init__(
         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 @@ def __init__(
         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 @@ def __init__(
         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 @@ def deploy_container(
         ex_instance_type=None,
         ex_timeout=default_time_out,
     ):
-
         """
         Create a new container
         Authentication: trusted
@@ -579,7 +569,6 @@ def deploy_container(
             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 @@ def deploy_container(
         return container
 
     def get_container(self, id, ex_get_ip_addr=True):
-
         """
         Get a container by ID
 
@@ -748,7 +736,6 @@ def restart_container(
         )
 
     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_freeze_container(self, container, ex_timeout=default_time_out):
         )
 
     def ex_unfreeze_container(self, container, ex_timeout=default_time_out):
-
         """
         Set the given container into  unfreeze state
 
@@ -819,14 +805,12 @@ def destroy_container(self, container, ex_timeout=default_time_out):
             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 @@ def ex_execute_cmd_on_container(self, cont_id, command, **config):
             )
 
         elif input["wait-for-websocket"] is True and input["interactive"] is True:
-
             return LXDContainerExecuteResult(
                 uuid=uuid,
                 secret_0=fds["0"],
@@ -964,7 +947,6 @@ def ex_execute_cmd_on_container(self, cont_id, command, **config):
             )
 
         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 @@ def ex_execute_cmd_on_container(self, cont_id, command, **config):
             )
 
         else:
-
             result = response_dict["metadata"]["metadata"]["result"]
             return LXDContainerExecuteResult(
                 uuid=uuid,
@@ -1054,7 +1035,6 @@ def ex_get_image(self, fingerprint):
         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 @@ def install_image(self, path, ex_timeout=default_time_out, **ex_img_data):
         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 @@ def ex_get_storage_pool(self, id):
         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 @@ def ex_list_storage_pool_volumes(self, pool_id, detailed=True):
             type = volume[-2]
 
             if not detailed:
-
                 metadata = {
                     "config": {"size": None},
                     "name": name,
@@ -1393,7 +1369,6 @@ def ex_get_volume_by_name(self, name, vol_type="custom"):
         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 @@ def ex_get_volume_by_name(self, name, vol_type="custom"):
         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 @@ def attach_volume(
         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 @@ def ex_delete_storage_pool_volume(self, pool_id, type, name):
         """
 
         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 8bf423dd1f..1e68d5f4ee 100644
--- a/libcloud/container/drivers/rancher.py
+++ b/libcloud/container/drivers/rancher.py
@@ -66,7 +66,6 @@ def __repr__(self):
 
 
 class RancherConnection(ConnectionUserAndKey):
-
     responseCls = RancherResponse
     timeout = 30
 
diff --git a/libcloud/dns/base.py b/libcloud/dns/base.py
index a358b9229d..f878447449 100644
--- a/libcloud/dns/base.py
+++ b/libcloud/dns/base.py
@@ -36,7 +36,7 @@ def __init__(
         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 @@ def __init__(
         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 12d2db578d..7cf02eb06c 100644
--- a/libcloud/dns/drivers/cloudflare.py
+++ b/libcloud/dns/drivers/cloudflare.py
@@ -200,7 +200,6 @@ class CloudFlareDNSDriver(DNSDriver):
     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 45d7480c1c..b2f609f254 100644
--- a/libcloud/dns/drivers/linode.py
+++ b/libcloud/dns/drivers/linode.py
@@ -87,7 +87,6 @@ def __new__(
         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 e147f59c81..bdff9bdfcd 100644
--- a/libcloud/dns/drivers/vultr.py
+++ b/libcloud/dns/drivers/vultr.py
@@ -93,7 +93,6 @@ def __new__(
 
 
 class VultrDNSDriverV1(VultrDNSDriver):
-
     connectionCls = VultrDNSConnection
 
     RECORD_TYPE_MAP = {
diff --git a/libcloud/loadbalancer/drivers/alb.py b/libcloud/loadbalancer/drivers/alb.py
index 34286f4e4e..8ab3ea46eb 100644
--- a/libcloud/loadbalancer/drivers/alb.py
+++ b/libcloud/loadbalancer/drivers/alb.py
@@ -68,7 +68,6 @@ def __init__(
         balancers=[],
         members=[],
     ):
-
         self.id = target_group_id
         self.name = name
         self.protocol = protocol
@@ -135,7 +134,6 @@ def __init__(
         ssl_certificate="",
         rules=[],
     ):
-
         self.id = listener_id
         self.protocol = protocol
         self.port = port
@@ -186,7 +184,6 @@ def __init__(
         conditions={},
         listener=None,
     ):
-
         self.id = rule_id
         self.is_default = is_default
         self.priority = priority
@@ -882,7 +879,6 @@ def _to_target_groups(self, data):
         ]
 
     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 6ff379f8cd..11644d44ab 100644
--- a/libcloud/loadbalancer/drivers/dimensiondata.py
+++ b/libcloud/loadbalancer/drivers/dimensiondata.py
@@ -78,7 +78,6 @@ def __init__(
         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 13511197fd..9fa5eecc84 100644
--- a/libcloud/loadbalancer/drivers/gce.py
+++ b/libcloud/loadbalancer/drivers/gce.py
@@ -36,7 +36,6 @@ class GCELBDriver(Driver):
     _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 9f660426da..ecd1499f4c 100644
--- a/libcloud/loadbalancer/drivers/nttcis.py
+++ b/libcloud/loadbalancer/drivers/nttcis.py
@@ -82,7 +82,6 @@ def __init__(
         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 836cc5d553..496eccb079 100644
--- a/libcloud/pricing.py
+++ b/libcloud/pricing.py
@@ -193,7 +193,6 @@ def get_size_price(driver_type, driver_name, size_id, region=None):
 
 
 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 @@ def _get_gce_image_price(image_name, size_name, cores=1):
     :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 763cbb8ad3..1fafbe9efd 100644
--- a/libcloud/storage/drivers/azure_blobs.py
+++ b/libcloud/storage/drivers/azure_blobs.py
@@ -1221,7 +1221,6 @@ def _upload_directly(
         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 25b45f3992..3ea831101c 100644
--- a/libcloud/storage/drivers/backblaze_b2.py
+++ b/libcloud/storage/drivers/backblaze_b2.py
@@ -554,7 +554,6 @@ def _get_object_download_path(self, container, obj):
     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 9f749b4462..c126c11b0d 100644
--- a/libcloud/storage/drivers/cloudfiles.py
+++ b/libcloud/storage/drivers/cloudfiles.py
@@ -192,23 +192,19 @@ def __init__(self, user_id, key, secure=True, use_internal_url=False, **kwargs):
     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 f898fe91a4..5e0bc7bae6 100644
--- a/libcloud/storage/drivers/digitalocean_spaces.py
+++ b/libcloud/storage/drivers/digitalocean_spaces.py
@@ -49,7 +49,6 @@ def __init__(
         backoff=None,
         **kwargs,
     ):
-
         super().__init__(
             user_id,
             key,
@@ -82,7 +81,6 @@ def __init__(
         backoff=None,
         **kwargs,
     ):
-
         super().__init__(
             user_id,
             key,
@@ -115,7 +113,6 @@ def __init__(
         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 0d42931030..a1bafdd21a 100644
--- a/libcloud/storage/drivers/minio.py
+++ b/libcloud/storage/drivers/minio.py
@@ -39,7 +39,6 @@ def __init__(
         backoff=None,
         **kwargs,
     ):
-
         super().__init__(
             user_id,
             key,
diff --git a/libcloud/storage/drivers/oss.py b/libcloud/storage/drivers/oss.py
index a3aa4b45ce..b43cdaa67a 100644
--- a/libcloud/storage/drivers/oss.py
+++ b/libcloud/storage/drivers/oss.py
@@ -545,7 +545,6 @@ def finder(node, text):
             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 @@ def _commit_multipart(self, object_path, upload_id, chunks, container=None):
 
         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 088c988385..ba8caede16 100644
--- a/libcloud/storage/drivers/rgw.py
+++ b/libcloud/storage/drivers/rgw.py
@@ -56,7 +56,6 @@ def __init__(
         backoff=None,
         **kwargs,
     ):
-
         super().__init__(
             user_id,
             key,
@@ -89,7 +88,6 @@ def __init__(
         backoff=None,
         **kwargs,
     ):
-
         super().__init__(
             user_id,
             key,
@@ -120,7 +118,6 @@ def __init__(
         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 31ef851b94..a46a7bd004 100644
--- a/libcloud/storage/drivers/s3.py
+++ b/libcloud/storage/drivers/s3.py
@@ -725,7 +725,7 @@ def _commit_multipart(self, container, object_name, upload_id, chunks):
         """
         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 @@ def _to_storage_class_headers(self, storage_class):
         """
         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/utils/decorators.py b/libcloud/utils/decorators.py
index 847933f524..1538e32545 100644
--- a/libcloud/utils/decorators.py
+++ b/libcloud/utils/decorators.py
@@ -34,7 +34,6 @@ def decorated_function(*args, **kwargs):
         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 bc5ffe3766..0000000000
--- 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 7a2fe8b87d..6c510ca122 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 @@ line_length = 99
 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/requirements-docs.txt b/requirements-docs.txt
index 01227da465..7b7ec59798 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 8cd7452e53..a027393cbd 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'
diff --git a/requirements-mypy.txt b/requirements-mypy.txt
index ab556f4411..9ca1dccb1d 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/setup.py b/setup.py
index cd96eaab91..10b3d46182 100644
--- a/setup.py
+++ b/setup.py
@@ -321,6 +321,7 @@ def run(self):
         "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 efdf9ecf3d..4d3affb2a9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -19,6 +19,7 @@ allowlist_externals =
     /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 @@ setenv =
 # 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 @@ setenv =
     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 @@ commands = flake8 --config ./.flake8 libcloud/
 [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 @@ setenv =
 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 @@ setenv =
   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 @@ commands =
 [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 =


Test patch:
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 864028402a..261a198d2c 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 @@ jobs:
           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/.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/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index 1183e7bd04..9f61f1ba3a 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -16,6 +16,11 @@ permissions:
   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 @@ jobs:
 
       - 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/libcloud/test/backup/test_dimensiondata_v2_3.py b/libcloud/test/backup/test_dimensiondata_v2_3.py
index eb666cfb00..46110ed7d7 100644
--- a/libcloud/test/backup/test_dimensiondata_v2_3.py
+++ b/libcloud/test/backup/test_dimensiondata_v2_3.py
@@ -303,7 +303,6 @@ def __init__(self, tag):
 
 
 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 939a6b5f4b..2156c423a5 100644
--- a/libcloud/test/backup/test_dimensiondata_v2_4.py
+++ b/libcloud/test/backup/test_dimensiondata_v2_4.py
@@ -303,7 +303,6 @@ def __init__(self, tag):
 
 
 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 631680bb75..ad49df9076 100644
--- a/libcloud/test/common/test_cloudstack.py
+++ b/libcloud/test/common/test_cloudstack.py
@@ -117,7 +117,6 @@ def test_signature_algorithm(self):
 
 
 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 0b4250c61c..4303f44aac 100644
--- a/libcloud/test/common/test_google.py
+++ b/libcloud/test/common/test_google.py
@@ -357,7 +357,6 @@ def test_guess_gce_metadata_server_not_called_for_ia(self):
 
 
 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_identity.py b/libcloud/test/common/test_openstack_identity.py
index f8545a3cf0..8f6b55066c 100644
--- a/libcloud/test/common/test_openstack_identity.py
+++ b/libcloud/test/common/test_openstack_identity.py
@@ -98,8 +98,8 @@ def test_auth_url_is_correctly_assembled(self):
         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 @@ def test_basic_authentication(self):
         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 @@ def test_authentication_cache(self):
         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 0000000000..b9702f2a89
--- /dev/null
+++ b/libcloud/test/compute/fixtures/azure_arm/_77777777_7777_7777_7777_777777777777_oauth2_token_PAGINATION_INFINITE_LOOP.json
@@ -0,0 +1,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 019c5c7b27..4c40f57cd6 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 0000000000..1b63cd9525
--- /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 0000000000..8c9e9135d8
--- /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 0000000000..0ac000f292
--- /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 0000000000..868bb53dbe
--- /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 373463389e..13ae1b8901 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_action
     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 5d50b8d3fd..b42507c34b 100644
--- a/libcloud/test/compute/test_azure.py
+++ b/libcloud/test/compute/test_azure.py
@@ -118,7 +118,6 @@ def test_list_nodes_returned_no_cloud_service(self):
             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 @@ def test_restart_node_success(self):
 
     #  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_deployment(self):
             )
 
     def test_restart_node_fail_no_cloud_service(self):
-
         node = Node(
             id="dc03",
             name="dc03",
@@ -173,7 +170,6 @@ def test_restart_node_fail_no_cloud_service(self):
             )
 
     def test_restart_node_fail_node_not_found(self):
-
         node = Node(
             id="dc13",
             name="dc13",
@@ -191,7 +187,6 @@ def test_restart_node_fail_node_not_found(self):
         self.assertFalse(result)
 
     def test_destroy_node_success_single_node_in_cloud_service(self):
-
         node = Node(
             id="oddkinz1",
             name="oddkinz1",
@@ -207,7 +202,6 @@ def test_destroy_node_success_single_node_in_cloud_service(self):
         self.assertTrue(result)
 
     def test_destroy_node_success_multiple_nodes_in_cloud_service(self):
-
         node = Node(
             id="oddkinz1",
             name="oddkinz1",
@@ -223,7 +217,6 @@ def test_destroy_node_success_multiple_nodes_in_cloud_service(self):
         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_fail_node_does_not_exist(self):
             )
 
     def test_destroy_node_success_cloud_service_not_found(self):
-
         node = Node(
             id="cloudredis",
             name="cloudredis",
@@ -354,7 +346,6 @@ def test_create_node_and_deployment_second_node(self):
 
 
 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(
     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_services_hostedservices_testdcabc2_dep
     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 85b320d6b2..b81fb24b5d 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,15 +445,32 @@ def error(e, **kwargs):
     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,
@@ -461,13 +478,18 @@ def test_list_nodes(self, fps_mock):
     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 @@ def test_list_snapshots(self):
         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 @@ def fn(method, url, body, headers):
                 "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 d0c3b4d3a5..a0deb3a664 100644
--- a/libcloud/test/compute/test_cloudsigma_v1_0.py
+++ b/libcloud/test/compute/test_cloudsigma_v1_0.py
@@ -152,24 +152,19 @@ def _drives_standard_info(self, method, url, body, headers):
         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 @@ def _resources_ip_1_2_3_4_destroy(self, method, url, body, headers):
         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 469e9691f7..6f9907d6e7 100644
--- a/libcloud/test/compute/test_cloudstack.py
+++ b/libcloud/test/compute/test_cloudstack.py
@@ -341,7 +341,6 @@ def test_ex_create_network(self):
         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 @@ def test_ex_list_nics(self):
             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 @@ def test_ex_add_nic_to_node(self):
         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 @@ def test_ex_create_vpc(self):
         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 c0befbeb16..0113de55c6 100644
--- a/libcloud/test/compute/test_dimensiondata_v2_3.py
+++ b/libcloud/test/compute/test_dimensiondata_v2_3.py
@@ -2198,7 +2198,6 @@ def __init__(self, tag):
 
 
 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_portList_c8c92ea3_2da
     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_createPortList(
     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 f26cea53e5..ec4c2b3f81 100644
--- a/libcloud/test/compute/test_dimensiondata_v2_4.py
+++ b/libcloud/test/compute/test_dimensiondata_v2_4.py
@@ -2294,7 +2294,6 @@ def __init__(self, tag):
 
 
 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_portList_c8c92ea3_2da
     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_createPortList(
     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 f21eab8246..19b9832bb7 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 @@ def test_create_node(self):
 
 
 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 a42e8e1e83..ee16fb3cf3 100644
--- a/libcloud/test/compute/test_kamatera.py
+++ b/libcloud/test/compute/test_kamatera.py
@@ -209,7 +209,6 @@ def ex_wait_command(self, *args, **kwargs):
 
 
 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 e5afafa329..0d89fac59c 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 @@ def test_reboot_node(self):
 
 
 class KubeVirtMockHttp(MockHttp):
-
     fixtures = ComputeFileFixtures("kubevirt")
 
     def _api_v1_namespaces(self, method, url, body, headers):
@@ -199,7 +197,6 @@ def _apis_kubevirt_io_v1alpha3_namespaces_default_virtualmachineinstances_testvm
         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 ff45d0863d..2a46477ee1 100644
--- a/libcloud/test/compute/test_nttcis.py
+++ b/libcloud/test/compute/test_nttcis.py
@@ -2107,7 +2107,6 @@ def __init__(self, tag):
 
 
 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_portList_c8c92ea3_2da
     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_createPortList(
     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 b683249f0a..e8bf332222 100644
--- a/libcloud/test/compute/test_openstack.py
+++ b/libcloud/test/compute/test_openstack.py
@@ -722,7 +722,6 @@ def _v1_0_slug_shared_ip_groups_5467(self, method, url, body, headers):
         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 @@ def test_list_sizes(self):
         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 24b0a67c46..1a05b5ae91 100644
--- a/libcloud/test/compute/test_rackspace.py
+++ b/libcloud/test/compute/test_rackspace.py
@@ -164,7 +164,6 @@ def test_list_sizes_pricing(self):
 
 
 class RackspaceNovaDfwTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
     driver_klass = RackspaceNodeDriver
     driver_type = RackspaceNodeDriver
     driver_args = RACKSPACE_NOVA_PARAMS
@@ -174,7 +173,6 @@ class RackspaceNovaDfwTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
 
 
 class RackspaceNovaOrdTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
     driver_klass = RackspaceNodeDriver
     driver_type = RackspaceNodeDriver
     driver_args = RACKSPACE_NOVA_PARAMS
@@ -184,7 +182,6 @@ class RackspaceNovaOrdTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
 
 
 class RackspaceNovaIadTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
     driver_klass = RackspaceNodeDriver
     driver_type = RackspaceNodeDriver
     driver_args = RACKSPACE_NOVA_PARAMS
@@ -194,7 +191,6 @@ class RackspaceNovaIadTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
 
 
 class RackspaceNovaLonTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
     driver_klass = RackspaceNodeDriver
     driver_type = RackspaceNodeDriver
     driver_args = RACKSPACE_NOVA_PARAMS
@@ -207,7 +203,6 @@ class RackspaceNovaLonTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
 
 
 class RackspaceNovaSydTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
-
     driver_klass = RackspaceNodeDriver
     driver_type = RackspaceNodeDriver
     driver_args = RACKSPACE_NOVA_PARAMS
@@ -217,7 +212,6 @@ class RackspaceNovaSydTests(BaseRackspaceNovaTestCase, OpenStack_1_1_Tests):
 
 
 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 82f1237b88..3af9fddaed 100644
--- a/libcloud/test/compute/test_rimuhosting.py
+++ b/libcloud/test/compute/test_rimuhosting.py
@@ -72,7 +72,6 @@ def test_create_node(self):
 
 
 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 3df531e972..981f788bf5 100644
--- a/libcloud/test/compute/test_vcloud.py
+++ b/libcloud/test/compute/test_vcloud.py
@@ -636,7 +636,13 @@ def test_remove_admin_password(self):
     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 @@ def test_get_auth_headers(self):
 
 
 class TerremarkMockHttp(MockHttp):
-
     fixtures = ComputeFileFixtures("terremark")
 
     def _api_v0_8_login(self, method, url, body, headers):
@@ -1072,7 +1077,6 @@ class AnotherError(Exception):
 
 
 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 c2593d3d71..c328a98d5d 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 @@ def test_reboot_node(self):
 
 
 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 5b5300b717..a9a437c5b1 100644
--- a/libcloud/test/container/test_lxd.py
+++ b/libcloud/test/container/test_lxd.py
@@ -201,7 +201,6 @@ def _linux_124_images_54c8caac1f61901ed86c68f24af5f5d3672bdc62c71d04f06df3a59e95
         )
 
     def _linux_124_containers(self, method, url, body, headers):
-
         if method == "GET":
             return (
                 httplib.OK,
@@ -228,7 +227,6 @@ def _linux_124_containers_first_lxd_container(self, method, url, body, headers):
         )
 
     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_second_lxd_container(self, method, url, body, headers)
             )
 
     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 @@ def _linux_124_containers_first_lxd_container_state(self, method, url, body, hea
             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_operations_1_wait(self, method, url, body, header):
         )
 
     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_pool1(self, method, url, body, header):
             )
 
     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_pool2(self, method, url, body, header):
             )
 
     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 1e7e3e40e7..a0135f1274 100644
--- a/libcloud/test/dns/test_liquidweb.py
+++ b/libcloud/test/dns/test_liquidweb.py
@@ -330,7 +330,6 @@ def _v1_Network_DNS_Record_ALREADY_EXISTS_ERROR(self, method, url, body, headers
         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 97406d2787..cc6cb94559 100644
--- a/libcloud/test/dns/test_luadns.py
+++ b/libcloud/test/dns/test_luadns.py
@@ -278,7 +278,6 @@ def _v1_zones_31_records_31_GET_RECORD_RECORD_DOES_NOT_EXIST(self, method, url,
         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 7a2b436517..5cdc2b2e13 100644
--- a/libcloud/test/loadbalancer/test_dimensiondata_v2_3.py
+++ b/libcloud/test/loadbalancer/test_dimensiondata_v2_3.py
@@ -490,7 +490,6 @@ def test_ex_get_default_irules(self):
 
 
 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 ab3347a4bb..e8f02cc2fd 100644
--- a/libcloud/test/loadbalancer/test_dimensiondata_v2_4.py
+++ b/libcloud/test/loadbalancer/test_dimensiondata_v2_4.py
@@ -490,7 +490,6 @@ def test_ex_get_default_irules(self):
 
 
 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 78b1f01c56..bdcfc5b9fe 100644
--- a/libcloud/test/loadbalancer/test_nttcis.py
+++ b/libcloud/test/loadbalancer/test_nttcis.py
@@ -628,7 +628,6 @@ def test_delete_ssl_domain_certificate(driver):
 
 
 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_deleteNode(
     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 4bc86fa270..cf4923dabf 100644
--- a/libcloud/test/loadbalancer/test_rackspace.py
+++ b/libcloud/test/loadbalancer/test_rackspace.py
@@ -1344,7 +1344,6 @@ def _v1_0_11111_loadbalancers_94699_accesslist(self, method, url, body, headers)
 
             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 1e6d70e3d3..a67e7dd79d 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 41db0c41ff..e9dc72c840 100644
--- a/libcloud/test/storage/test_base.py
+++ b/libcloud/test/storage/test_base.py
@@ -52,7 +52,6 @@ def setUp(self):
         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 213406288a..df4a73e5de 100644
--- a/libcloud/test/storage/test_cloudfiles.py
+++ b/libcloud/test/storage/test_cloudfiles.py
@@ -123,6 +123,14 @@ def test_service_catalog(self):
         )
         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 @@ def test_upload_object_via_stream_with_cors_headers(self):
         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 @@ def test_upload_object_via_stream_python3_bytes_error(self):
 
     @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 CloudFilesDeprecatedUKTests(CloudFilesTests):
 
 
 class CloudFilesMockHttp(BaseRangeDownloadMockHttp, unittest.TestCase):
-
     fixtures = StorageFileFixtures("cloudfiles")
     base_headers = {"content-type": "application/json; charset=UTF-8"}
 
@@ -1255,7 +1260,6 @@ def _v1_MossoCloudFS_foo_bar_container(self, method, url, body, headers):
         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(self, method, url, b
     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 @@ def _v1_MossoCloudFS_foo_bar_container_object_PURGE_SUCCESS_EMAIL(
         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 @@ def _v1_MossoCloudFS_foo_bar_container_NOT_FOUND(self, method, url, body, header
         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 @@ def _v1_MossoCloudFS_foo_bar_container_NOT_EMPTY(self, method, url, body, header
         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(self, method, url, b
     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 66394d4ce4..3debf9d0df 100644
--- a/libcloud/test/storage/test_oss.py
+++ b/libcloud/test/storage/test_oss.py
@@ -76,7 +76,6 @@ def test_object_with_chinese_name(self):
 
 
 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 e5ea383e0c..46aa60a2be 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 @@ def test_upload_small_object_via_stream(self):
         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 69d37059b8..49a480587f 100644
--- a/libcloud/test/test_utils.py
+++ b/libcloud/test/test_utils.py
@@ -479,7 +479,6 @@ def test_increment_ipv4_segments(self):
 
 
 class TestPublicKeyUtils(unittest.TestCase):
-
     PUBKEY = (
         "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDOfbWSXOlqvYjZmRO84/lIoV4gvuX+"
         "P1lLg50MMg6jZjLZIlYY081XPRmuom0xY0+BO++J2KgLl7gxJ6xMsKK2VQ+TakdfAH20"
diff --git a/pytest.ini b/pytest.ini
deleted file mode 100644
index cdecf5329e..0000000000
--- 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-tests.txt b/requirements-tests.txt
index e9e8c071e6..ac7d68b62e 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -1,15 +1,14 @@
-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