Skip to content

Commit

Permalink
Add support for Cloud Quota Management API (#29)
Browse files Browse the repository at this point in the history
Requests for work with `limits` and `quotas` are now sent to
Cloud Quota Management API instead of Cloud Management API, as
it was before.

Commands for working with limits and quotas have been changed.
Now the commands look like this:
selvpc quota set --region VALUE [--zone VALUE] --resource VALUE --value VALUE <project_id>
selvpc quota show --region VALUE <project_id>
selvpc limit show --region VALUE <project_id>

Cloud Quota Management API is a region service that works with
X-Auth-Token, opposite the Cloud Management API that works with
X-Token and is only in one region.

RegionalHTTPClient is a Proxy of the HTTPClient class, it resolves
the URL of the service in the requested region and adds X-Auth-Token to
the headers.

The functionality for issuing and caching the X-Auth-Token, as
well as resolving the service URL is encapsulated in
the IdentityManager class.

OPENSTACK-12283
  • Loading branch information
milkrage authored Dec 13, 2022
1 parent 9995506 commit d1fdd16
Show file tree
Hide file tree
Showing 31 changed files with 646 additions and 959 deletions.
4 changes: 2 additions & 2 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
sphinx_rtd_theme>=0.1.9
sphinx-pypi-upload-2>=0.2.2
sphinx_rtd_theme==1.1.1
sphinx-pypi-upload-2==0.2.2
12 changes: 7 additions & 5 deletions docs/usage/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ Command-line Interface
Basic Usage
-----------

In order to use the CLI, you must provide your Selectel VPC API token
and API endpoint. Use the corresponding configuration options
(``--url``, ``--token``), but it is easier to set them in environment variables.
In order to use the CLI, you must provide your Selectel VPC API token,
API endpoint and Keystone identity url. Use the corresponding configuration
options (``--url``, ``--token``, ``--identity_url``),
but it is easier to set them in environment variables.

.. code-block:: shell
export SEL_URL=url
export SEL_TOKEN=token
export SEL_API_VERSION=api_version # by default 2
export SEL_API_VERSION=api_version # by default: 2
export OS_AUTH_URL=url # by default: https://api.selvpc.ru/identity/v3
Once you've configured your authentication parameters, you can run **selvpc**
commands. All commands take the form of:
Expand Down Expand Up @@ -110,4 +112,4 @@ Commands
:glob:
:maxdepth: 2

commands
commands
11 changes: 4 additions & 7 deletions docs/usage/commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@ Manage customization
**--logo** param can be like URL to logo or local path.


Show domain limits
Show project limits
~~~~~~~~~~~~~~~~~~
.. code-block:: console
$ selvpc limit show
$ selvpc limit show free
$ selvpc limit show --region VALUE <project_id>
Manage projects
~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -61,10 +60,8 @@ Manage quotas
~~~~~~~~~~~~~
.. code-block:: console
$ selvpc quota list
$ selvpc quota optimize <project_id>
$ selvpc quota show <project_id>
$ selvpc quota set <project_id> --resource VALUE --region VALUE [--zone VALUE] --value VALUE
$ selvpc quota show --region VALUE <project_id>
$ selvpc quota set --resource VALUE --region VALUE [--zone VALUE] --value VALUE <project_id>
.. note::
Key **zone** by default is empty.
Expand Down
28 changes: 18 additions & 10 deletions docs/usage/library.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,22 @@ API URL `here <https://support.selectel.ru/vpc/docs/>`_)

.. code-block:: python
>>> from selvpcclient.client import Client, setup_http_client
>>> SEL_TOKEN=YOUR_API_TOKEN_HERE
>>> SEL_URL="https://api.selectel.ru/vpc/resell"
>>> http_client = setup_http_client(api_url=SEL_URL, api_token=SEL_TOKEN)
>>> selvpc = Client(client=http_client)
>>> from selvpcclient.client import Client
>>> from selvpcclient.client import setup_http_client
>>> from selvpcclient.httpclient import RegionalHTTPClient
>>> SEL_TOKEN = YOUR_API_TOKEN_HERE
>>> SEL_URL = "https://api.selectel.ru/vpc/resell"
>>> OS_AUTH_URL = "https://api.selvpc.ru/identity/v3"
>>> http_client = setup_http_client(
... api_url=SEL_URL, api_token=SEL_TOKEN)
>>> regional_http_client = RegionalHTTPClient(
... http_client=http_client,
... identity_url=OS_AUTH_URL)
>>> selvpc = Client(client=http_client, regional_client=regional_http_client)
Now you can call various methods on the client instance. For example

Expand Down Expand Up @@ -48,14 +59,12 @@ Set project quotas
"quotas": {
"compute_cores": [
{
"region": "ru-1",
"zone": "ru-1a",
"value": 10
}
],
"compute_ram": [
{
"region": "ru-1",
"zone": "ru-1a",
"value": 1024
}
Expand All @@ -64,11 +73,10 @@ Set project quotas
}
# via object
>>> project.update_quotas(quotas)
>>> project.update_quotas("ru-1", quotas)
# via quotas manager
>>> quotas = selvpc.quotas.update(project.id, quotas=quotas)
>>> quotas = selvpc.quotas.update_project_quotas(project.id, "ru-1", quotas)
Add Windows license
~~~~~~~~~~~~~~~~~~~
Expand Down
1 change: 1 addition & 0 deletions env.example.bat
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
:: Required variables
set SEL_TOKEN=MNhA6zVcf7x892LqsQSc9vDN_9999
set SEL_URL=https://api.selectel.ru/vpc/resell
set OS_AUTH_URL=https://api.selvpc.ru/identity/v3

:: Optional variables
set SEL_API_VERSION=2
1 change: 1 addition & 0 deletions env.example.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Required variables
export SEL_TOKEN=MNhA6zVcf7x892LqsQSc9vDN_9999
export SEL_URL=https://api.selectel.ru/vpc/resell
export OS_AUTH_URL=https://api.selvpc.ru/identity/v3

# Optional variables
export SEL_API_VERSION=2
27 changes: 21 additions & 6 deletions examples/first_project/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os

from selvpcclient.client import Client, setup_http_client
from selvpcclient.httpclient import RegionalHTTPClient

logging.basicConfig(level=logging.INFO)

Expand All @@ -17,43 +18,57 @@
#
VPC_URL = "https://api.selectel.ru/vpc/resell"

#
# Keystone identity URL
# You can get actual api URL here
# https://support.selectel.ru/vpc/docs
#
IDENTITY_URL = os.getenv('OS_AUTH_URL', 'https://api.selvpc.ru/identity/v3')

REGION = "ru-2"
ZONE = "ru-2a"
ZONE = "ru-2c"

http_client = setup_http_client(api_url=VPC_URL, api_token=VPC_TOKEN)
selvpc = Client(client=http_client)
regional_http_client = RegionalHTTPClient(http_client=http_client,
identity_url=IDENTITY_URL)

selvpc = Client(client=http_client, regional_client=regional_http_client)

project = selvpc.projects.create(name="Awesome Projectq12")
logging.info(
"Project '%s' has been created with id '%s'", project.name, project.id)

project_limits = selvpc.quotas.get_project_limits(project_id=project.id,
region=REGION)

logging.info(f"Project limits received. "
f"Limits for resource `compute_cores` in region `{REGION}`: "
f"{project_limits.compute_cores}")

quotas = {
"quotas": {
"compute_cores": [
{
"region": REGION,
"zone": ZONE,
"value": 1
}
],
"compute_ram": [
{
"region": REGION,
"zone": ZONE,
"value": 512
}
],
"volume_gigabytes_fast": [
{
"region": REGION,
"zone": ZONE,
"value": 5
}
]
}
}

project.update_quotas(quotas)
project.update_quotas(region=REGION, quotas=quotas)
logging.info("Project quotas has been set")

floating_ips = {
Expand Down
12 changes: 7 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cliff>=2.2
pbr>=1.8
requests>=2.9.1
six>=1.9.0
PyYAML>=3.10
cliff==3.10.1
pbr==5.11.0
requests==2.28.1
six==1.16.0
PyYAML==6.0
python-keystoneclient==4.5.0
importlib-metadata==4.13.0
2 changes: 1 addition & 1 deletion selvpcclient/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.4"
__version__ = "2.0"
4 changes: 2 additions & 2 deletions selvpcclient/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from cliff.lister import Lister
from cliff.show import ShowOne

from selvpcclient.util import get_item_properties, process_partial_quotas
from selvpcclient.util import get_item_properties

log = logging.getLogger(__name__)

Expand All @@ -17,7 +17,7 @@ class PartialResponse(object):

def __init__(self, manager, ok, fail):
if manager.resource_class.__name__ == "Quotas":
self.resources = Resource(manager, process_partial_quotas(ok))
self.resources = Resource(manager, ok)
self._info = self.resources._info
else:
self._info = ok
Expand Down
22 changes: 18 additions & 4 deletions selvpcclient/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import os

from selvpcclient import __version__
from selvpcclient.httpclient import HTTPClient
from selvpcclient.httpclient import HTTPClient, RegionalHTTPClient
from selvpcclient.resources.capabilities import CapabilitiesManager
from selvpcclient.resources.customization import CustomizationManager
from selvpcclient.resources.floatingips import FloatingIPManager
Expand Down Expand Up @@ -42,9 +44,21 @@ def setup_http_client(api_url, api_token=None, api_version=2,
class Client:
"""Client for the Selectel VPC API."""

def __init__(self, client):
self.projects = ProjectsManager(client)
self.quotas = QuotasManager(client)
def __init__(
self,
client: HTTPClient,
regional_client: RegionalHTTPClient = None
):
if not regional_client:
regional_client = RegionalHTTPClient(
http_client=client,
identity_url=os.environ.get(
'OS_AUTH_URL', 'https://api.selvpc.ru/identity/v3'
)
)

self.projects = ProjectsManager(client, regional_client)
self.quotas = QuotasManager(regional_client)
self.users = UsersManager(client)
self.licenses = LicenseManager(client)
self.roles = RolesManager(client)
Expand Down
5 changes: 1 addition & 4 deletions selvpcclient/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,10 @@
'project show': project.Show,
'project delete': project.Delete,

'limit show': limit.List,
'limit show free': limit.Free,
'limit show': limit.Show,

'quota list': quotas.List,
'quota set': quotas.Update,
'quota show': quotas.Show,
'quota optimize': quotas.Optimize,

'license add': license.Add,
'license list': license.List,
Expand Down
46 changes: 23 additions & 23 deletions selvpcclient/commands/limit.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
from selvpcclient.base import ListCommand
from selvpcclient.formatters import join_by_key, reformat_quotas
from selvpcclient.formatters import join_by_key, reformat_limits
from selvpcclient.util import handle_http_error


class List(ListCommand):
"""Show domain quotas"""
class Show(ListCommand):
"""Show project limits"""

columns = ["resource", "region", "zone", "value"]
columns = ["resource", "zone", "value"]
_formatters = {
"region": join_by_key("region"),
"zone": join_by_key("zone"),
"value": join_by_key("value")
}
sorting_support = True

@handle_http_error
def take_action(self, parsed_args):
result = self.app.context["client"].quotas.get_domain_quotas()
return self.setup_columns(reformat_quotas(result._info), parsed_args)


class Free(ListCommand):
"""Show free domain quotas"""

columns = ["resource", "region", "zone", "value"]
_formatters = {
"region": join_by_key("region"),
"zone": join_by_key("zone"),
"value": join_by_key("value")
}
sorting_support = True
def get_parser(self, prog_name):
parser = super(ListCommand, self).get_parser(prog_name)
required = parser.add_argument_group('Required arguments')
required.add_argument('-r',
'--region',
required=True,
)
required.add_argument('project_id',
metavar='<project_id>',
)
return parser

@handle_http_error
def take_action(self, parsed_args):
result = self.app.context["client"].quotas.get_free_domain_quotas()
return self.setup_columns(reformat_quotas(result._info), parsed_args)
result = self.app.context["client"].quotas.get_project_limits(
project_id=parsed_args.project_id,
region=parsed_args.region
)

return self.setup_columns(
reformat_limits(result._info), parsed_args
)
8 changes: 1 addition & 7 deletions selvpcclient/commands/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,11 @@ def get_parser(self, prog_name):
'--name',
required=True,
)
optional = parser.add_argument_group('Optional arguments')
optional.add_argument('--auto-quotas',
default=False,
action='store_true',
)
return parser

@handle_http_error
def take_action(self, parsed_args):
result = self.app.context["client"].projects.create(
parsed_args.name, auto_quotas=parsed_args.auto_quotas)
result = self.app.context["client"].projects.create(parsed_args.name)
return self.setup_columns(result, parsed_args)


Expand Down
Loading

0 comments on commit d1fdd16

Please sign in to comment.