mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-13 13:17:54 +03:00
added proxy support for OpenStack & OpenStack legacy
This commit is contained in:
parent
6e438bf4cb
commit
09c65b2598
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2016-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2016-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -12,7 +12,7 @@
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
@ -35,6 +35,7 @@ import json
|
||||
import typing
|
||||
|
||||
import requests
|
||||
|
||||
# import dateutil.parser
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
@ -57,10 +58,17 @@ VERIFY_SSL = False
|
||||
|
||||
|
||||
# Helpers
|
||||
def ensureResponseIsValid(response: requests.Response, errMsg: typing.Optional[str] = None) -> None:
|
||||
def ensureResponseIsValid(
|
||||
response: requests.Response, errMsg: typing.Optional[str] = None
|
||||
) -> None:
|
||||
if response.ok is False:
|
||||
try:
|
||||
_, err = response.json().popitem() # Extract any key, in case of error is expected to have only one top key so this will work
|
||||
(
|
||||
_,
|
||||
err,
|
||||
) = (
|
||||
response.json().popitem()
|
||||
) # Extract any key, in case of error is expected to have only one top key so this will work
|
||||
msg = ': {message}'.format(**err)
|
||||
errMsg = errMsg + msg if errMsg else msg
|
||||
except Exception:
|
||||
@ -72,18 +80,21 @@ def ensureResponseIsValid(response: requests.Response, errMsg: typing.Optional[s
|
||||
|
||||
|
||||
def getRecurringUrlJson(
|
||||
url: str,
|
||||
headers: typing.Dict[str, str],
|
||||
key: str,
|
||||
params: typing.Dict[str, str] = None,
|
||||
errMsg: str = None,
|
||||
timeout: int = 10
|
||||
) -> typing.Iterable[typing.Any]:
|
||||
url: str,
|
||||
session: requests.Session,
|
||||
headers: typing.Dict[str, str],
|
||||
key: str,
|
||||
params: typing.Dict[str, str] = None,
|
||||
errMsg: str = None,
|
||||
timeout: int = 10,
|
||||
) -> typing.Iterable[typing.Any]:
|
||||
counter = 0
|
||||
while True:
|
||||
counter += 1
|
||||
logger.debug('Requesting url #%s: %s / %s', counter, url, params)
|
||||
r = requests.get(url, params=params, headers=headers, verify=VERIFY_SSL, timeout=timeout)
|
||||
r = session.get(
|
||||
url, params=params, headers=headers, verify=VERIFY_SSL, timeout=timeout
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, errMsg)
|
||||
|
||||
@ -97,6 +108,7 @@ def getRecurringUrlJson(
|
||||
|
||||
url = j['next']
|
||||
|
||||
|
||||
RT = typing.TypeVar('RT')
|
||||
|
||||
# Decorators
|
||||
@ -114,7 +126,7 @@ def authRequired(func: typing.Callable[..., RT]) -> typing.Callable[..., RT]:
|
||||
|
||||
def authProjectRequired(func: typing.Callable[..., RT]) -> typing.Callable[..., RT]:
|
||||
def ensurer(obj, *args, **kwargs) -> RT:
|
||||
if obj._projectId is None: # pylint: disable=protected-access
|
||||
if obj._projectId is None: # pylint: disable=protected-access
|
||||
raise Exception('Need a project for method {}'.format(func))
|
||||
obj.ensureAuthenticated()
|
||||
return func(obj, *args, **kwargs)
|
||||
@ -142,21 +154,27 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
_project: typing.Optional[str]
|
||||
_region: typing.Optional[str]
|
||||
_timeout: int
|
||||
_session: requests.Session
|
||||
|
||||
# Legacyversion is True for versions <= Ocata
|
||||
def __init__(
|
||||
self,
|
||||
host: str,
|
||||
port: typing.Union[str, int],
|
||||
domain: str,
|
||||
username: str,
|
||||
password: str,
|
||||
legacyVersion: bool = True,
|
||||
useSSL: bool = False,
|
||||
projectId: typing.Optional[str] = None,
|
||||
region: typing.Optional[str] = None,
|
||||
access: typing.Optional[str] = None
|
||||
):
|
||||
self,
|
||||
host: str,
|
||||
port: typing.Union[str, int],
|
||||
domain: str,
|
||||
username: str,
|
||||
password: str,
|
||||
legacyVersion: bool = True,
|
||||
useSSL: bool = False,
|
||||
projectId: typing.Optional[str] = None,
|
||||
region: typing.Optional[str] = None,
|
||||
access: typing.Optional[str] = None,
|
||||
proxies: typing.Optional[typing.MutableMapping[str, str]] = None,
|
||||
):
|
||||
self._session = requests.Session()
|
||||
if proxies:
|
||||
self._session.proxies = proxies
|
||||
|
||||
self._authenticated = False
|
||||
self._authenticatedProjectId = None
|
||||
self._tokenId = None
|
||||
@ -178,7 +196,9 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
if self._authUrl[-1] != '/':
|
||||
self._authUrl += '/'
|
||||
|
||||
def _getEndpointFor(self, type_: str) -> str: # If no region is indicatad, first endpoint is returned
|
||||
def _getEndpointFor(
|
||||
self, type_: str
|
||||
) -> str: # If no region is indicatad, first endpoint is returned
|
||||
if not self._catalog:
|
||||
raise Exception('No catalog for endpoints')
|
||||
for i in filter(lambda v: v['type'] == type_, self._catalog):
|
||||
@ -199,18 +219,18 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
data: typing.Dict[str, typing.Any] = {
|
||||
'auth': {
|
||||
'identity': {
|
||||
'methods': [
|
||||
'password'
|
||||
],
|
||||
'methods': ['password'],
|
||||
'password': {
|
||||
'user': {
|
||||
'name': self._username,
|
||||
'domain': {
|
||||
'name': 'Default' if self._domain is None else self._domain
|
||||
'name': 'Default'
|
||||
if self._domain is None
|
||||
else self._domain
|
||||
},
|
||||
'password': self._password
|
||||
'password': self._password,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,22 +242,17 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
else:
|
||||
self._authenticatedProjectId = self._projectId
|
||||
data['auth']['scope'] = {
|
||||
'project': {
|
||||
'id': self._projectId,
|
||||
'domain': {
|
||||
'name': self._domain
|
||||
}
|
||||
}
|
||||
'project': {'id': self._projectId, 'domain': {'name': self._domain}}
|
||||
}
|
||||
|
||||
# logger.debug('Request data: {}'.format(data))
|
||||
|
||||
r = requests.post(
|
||||
r = self._session.post(
|
||||
self._authUrl + 'v3/auth/tokens',
|
||||
data=json.dumps(data),
|
||||
headers={'content-type': 'application/json'},
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Invalid Credentials')
|
||||
@ -257,59 +272,71 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
self._catalog = token['catalog']
|
||||
|
||||
def ensureAuthenticated(self) -> None:
|
||||
if self._authenticated is False or self._projectId != self._authenticatedProjectId:
|
||||
if (
|
||||
self._authenticated is False
|
||||
or self._projectId != self._authenticatedProjectId
|
||||
):
|
||||
self.authPassword()
|
||||
|
||||
@authRequired
|
||||
def listProjects(self) -> typing.Iterable[typing.Any]:
|
||||
return getRecurringUrlJson(
|
||||
self._authUrl + 'v3/users/{user_id}/projects'.format(user_id=self._userId),
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='projects',
|
||||
errMsg='List Projects',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authRequired
|
||||
def listRegions(self) -> typing.Iterable[typing.Any]:
|
||||
return getRecurringUrlJson(
|
||||
self._authUrl + 'v3/regions/',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='regions',
|
||||
errMsg='List Regions',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authProjectRequired
|
||||
def listServers(self, detail: bool = False, params: typing.Optional[typing.Dict[str, str]] = None) -> typing.Iterable[typing.Any]:
|
||||
def listServers(
|
||||
self,
|
||||
detail: bool = False,
|
||||
params: typing.Optional[typing.Dict[str, str]] = None,
|
||||
) -> typing.Iterable[typing.Any]:
|
||||
path = '/servers/' + 'detail' if detail is True else ''
|
||||
return getRecurringUrlJson(
|
||||
self._getEndpointFor('compute') + path,
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='servers',
|
||||
params=params,
|
||||
errMsg='List Vms',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authProjectRequired
|
||||
def listImages(self) -> typing.Iterable[typing.Any]:
|
||||
return getRecurringUrlJson(
|
||||
self._getEndpointFor('image') + '/v2/images?status=active',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='images',
|
||||
errMsg='List Images',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authProjectRequired
|
||||
def listVolumeTypes(self) -> typing.Iterable[typing.Any]:
|
||||
return getRecurringUrlJson(
|
||||
self._getEndpointFor('volumev2') + '/types',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='volume_types',
|
||||
errMsg='List Volume Types',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authProjectRequired
|
||||
@ -317,33 +344,38 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
# self._getEndpointFor('volumev2') + '/volumes'
|
||||
return getRecurringUrlJson(
|
||||
self._getEndpointFor('volumev2') + '/volumes/detail',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='volumes',
|
||||
errMsg='List Volumes',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authProjectRequired
|
||||
def listVolumeSnapshots(self, volumeId: typing.Optional[typing.Dict[str, typing.Any]] = None) -> typing.Iterable[typing.Any]:
|
||||
def listVolumeSnapshots(
|
||||
self, volumeId: typing.Optional[typing.Dict[str, typing.Any]] = None
|
||||
) -> typing.Iterable[typing.Any]:
|
||||
for s in getRecurringUrlJson(
|
||||
self._getEndpointFor('volumev2') + '/snapshots',
|
||||
headers=self._requestHeaders(),
|
||||
key='snapshots',
|
||||
errMsg='List snapshots',
|
||||
timeout=self._timeout
|
||||
):
|
||||
self._getEndpointFor('volumev2') + '/snapshots',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='snapshots',
|
||||
errMsg='List snapshots',
|
||||
timeout=self._timeout,
|
||||
):
|
||||
if volumeId is None or s['volume_id'] == volumeId:
|
||||
yield s
|
||||
|
||||
@authProjectRequired
|
||||
def listAvailabilityZones(self) -> typing.Iterable[typing.Any]:
|
||||
for az in getRecurringUrlJson(
|
||||
self._getEndpointFor('compute') + '/os-availability-zone',
|
||||
headers=self._requestHeaders(),
|
||||
key='availabilityZoneInfo',
|
||||
errMsg='List Availability Zones',
|
||||
timeout=self._timeout
|
||||
):
|
||||
self._getEndpointFor('compute') + '/os-availability-zone',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='availabilityZoneInfo',
|
||||
errMsg='List Availability Zones',
|
||||
timeout=self._timeout,
|
||||
):
|
||||
if az['zoneState']['available'] is True:
|
||||
yield az['zoneName']
|
||||
|
||||
@ -351,47 +383,55 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
def listFlavors(self) -> typing.Iterable[typing.Any]:
|
||||
return getRecurringUrlJson(
|
||||
self._getEndpointFor('compute') + '/flavors',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='flavors',
|
||||
errMsg='List Flavors',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authProjectRequired
|
||||
def listNetworks(self, nameFromSubnets=False) -> typing.Iterable[typing.Any]:
|
||||
nets = getRecurringUrlJson(
|
||||
self._getEndpointFor('network') + '/v2.0/networks',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='networks',
|
||||
errMsg='List Networks',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
if not nameFromSubnets:
|
||||
yield from nets
|
||||
else:
|
||||
# Get and cache subnets names
|
||||
subnetNames = { s['id']: s['name'] for s in self.listSubnets() }
|
||||
subnetNames = {s['id']: s['name'] for s in self.listSubnets()}
|
||||
for net in nets:
|
||||
name = ','.join(subnetNames[i] for i in net['subnets'] if i in subnetNames)
|
||||
name = ','.join(
|
||||
subnetNames[i] for i in net['subnets'] if i in subnetNames
|
||||
)
|
||||
net['old_name'] = net['name']
|
||||
if name:
|
||||
net['name'] = name
|
||||
|
||||
yield net
|
||||
|
||||
|
||||
@authProjectRequired
|
||||
def listSubnets(self) -> typing.Iterable[typing.Any]:
|
||||
return getRecurringUrlJson(
|
||||
self._getEndpointFor('network') + '/v2.0/subnets',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='subnets',
|
||||
errMsg='List Subnets',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authProjectRequired
|
||||
def listPorts(self, networkId: typing.Optional[str] = None, ownerId: typing.Optional[str] = None) -> typing.Iterable[typing.Any]:
|
||||
def listPorts(
|
||||
self,
|
||||
networkId: typing.Optional[str] = None,
|
||||
ownerId: typing.Optional[str] = None,
|
||||
) -> typing.Iterable[typing.Any]:
|
||||
params = {}
|
||||
if networkId is not None:
|
||||
params['network_id'] = networkId
|
||||
@ -400,41 +440,45 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
|
||||
return getRecurringUrlJson(
|
||||
self._getEndpointFor('network') + '/v2.0/ports',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='ports',
|
||||
params=params,
|
||||
errMsg='List ports',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authProjectRequired
|
||||
def listSecurityGroups(self) -> typing.Iterable[typing.Any]:
|
||||
return getRecurringUrlJson(
|
||||
self._getEndpointFor('compute') + '/os-security-groups',
|
||||
self._session,
|
||||
headers=self._requestHeaders(),
|
||||
key='security_groups',
|
||||
errMsg='List security groups',
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
@authProjectRequired
|
||||
def getServer(self, serverId: str) -> typing.Dict[str, typing.Any]:
|
||||
r = requests.get(
|
||||
self._getEndpointFor('compute') + '/servers/{server_id}'.format(server_id=serverId),
|
||||
r = self._session.get(
|
||||
self._getEndpointFor('compute')
|
||||
+ '/servers/{server_id}'.format(server_id=serverId),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
ensureResponseIsValid(r, 'Get Server information')
|
||||
return r.json()['server']
|
||||
|
||||
@authProjectRequired
|
||||
def getVolume(self, volumeId: str) -> typing.Dict[str, typing.Any]:
|
||||
r = requests.get(
|
||||
self._getEndpointFor('volumev2') + '/volumes/{volume_id}'.format(volume_id=volumeId),
|
||||
r = self._session.get(
|
||||
self._getEndpointFor('volumev2')
|
||||
+ '/volumes/{volume_id}'.format(volume_id=volumeId),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Get Volume information')
|
||||
@ -447,11 +491,12 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
States are:
|
||||
creating, available, deleting, error, error_deleting
|
||||
"""
|
||||
r = requests.get(
|
||||
self._getEndpointFor('volumev2') + '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
r = self._session.get(
|
||||
self._getEndpointFor('volumev2')
|
||||
+ '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Get Snaphost information')
|
||||
@ -459,22 +504,26 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
return r.json()['snapshot']
|
||||
|
||||
@authProjectRequired
|
||||
def updateSnapshot(self, snapshotId: str, name: typing.Optional[str] = None, description: typing.Optional[str] = None) -> typing.Dict[str, typing.Any]:
|
||||
data: typing.Dict[str, typing.Any] = {
|
||||
'snapshot': {}
|
||||
}
|
||||
def updateSnapshot(
|
||||
self,
|
||||
snapshotId: str,
|
||||
name: typing.Optional[str] = None,
|
||||
description: typing.Optional[str] = None,
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
data: typing.Dict[str, typing.Any] = {'snapshot': {}}
|
||||
if name:
|
||||
data['snapshot']['name'] = name
|
||||
|
||||
if description:
|
||||
data['snapshot']['description'] = description
|
||||
|
||||
r = requests.put(
|
||||
self._getEndpointFor('volumev2') + '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
r = self._session.put(
|
||||
self._getEndpointFor('volumev2')
|
||||
+ '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
data=json.dumps(data),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Update Snaphost information')
|
||||
@ -482,49 +531,55 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
return r.json()['snapshot']
|
||||
|
||||
@authProjectRequired
|
||||
def createVolumeSnapshot(self, volumeId: str, name: str, description: typing.Optional[str] = None) -> typing.Dict[str, typing.Any]:
|
||||
def createVolumeSnapshot(
|
||||
self, volumeId: str, name: str, description: typing.Optional[str] = None
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
description = description or 'UDS Snapshot'
|
||||
data = {
|
||||
'snapshot': {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'volume_id': volumeId,
|
||||
'force': True
|
||||
'force': True,
|
||||
}
|
||||
}
|
||||
|
||||
# First, ensure volume is in state "available"
|
||||
|
||||
r = requests.post(
|
||||
r = self._session.post(
|
||||
self._getEndpointFor('volumev2') + '/snapshots',
|
||||
data=json.dumps(data),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Cannot create snapshot. Ensure volume is in state "available"')
|
||||
ensureResponseIsValid(
|
||||
r, 'Cannot create snapshot. Ensure volume is in state "available"'
|
||||
)
|
||||
|
||||
return r.json()['snapshot']
|
||||
|
||||
@authProjectRequired
|
||||
def createVolumeFromSnapshot(self, snapshotId: str, name: str, description: typing.Optional[str] = None) -> typing.Dict[str, typing.Any]:
|
||||
def createVolumeFromSnapshot(
|
||||
self, snapshotId: str, name: str, description: typing.Optional[str] = None
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
description = description or 'UDS Volume'
|
||||
data = {
|
||||
'volume': {
|
||||
'name': name,
|
||||
'description': description,
|
||||
# 'volume_type': volType, # This seems to be the volume type name, not the id
|
||||
'snapshot_id': snapshotId
|
||||
'snapshot_id': snapshotId,
|
||||
}
|
||||
}
|
||||
|
||||
r = requests.post(
|
||||
r = self._session.post(
|
||||
self._getEndpointFor('volumev2') + '/volumes',
|
||||
data=json.dumps(data),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Cannot create volume from snapshot.')
|
||||
@ -533,47 +588,49 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
|
||||
@authProjectRequired
|
||||
def createServerFromSnapshot(
|
||||
self,
|
||||
snapshotId: str,
|
||||
name: str,
|
||||
availabilityZone: str,
|
||||
flavorId: str,
|
||||
networkId: str,
|
||||
securityGroupsIdsList: typing.Iterable[str],
|
||||
count: int = 1
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
self,
|
||||
snapshotId: str,
|
||||
name: str,
|
||||
availabilityZone: str,
|
||||
flavorId: str,
|
||||
networkId: str,
|
||||
securityGroupsIdsList: typing.Iterable[str],
|
||||
count: int = 1,
|
||||
) -> typing.Dict[str, typing.Any]:
|
||||
data = {
|
||||
'server': {
|
||||
'name': name,
|
||||
'imageRef': '',
|
||||
'metadata' : {
|
||||
'udsOwner' : 'xxxxx'
|
||||
},
|
||||
'metadata': {'udsOwner': 'xxxxx'},
|
||||
# 'os-availability-zone': availabilityZone,
|
||||
'availability_zone': availabilityZone,
|
||||
'block_device_mapping_v2': [{
|
||||
'boot_index': '0',
|
||||
'uuid': snapshotId,
|
||||
# 'volume_size': 1,
|
||||
# 'device_name': 'vda',
|
||||
'source_type': 'snapshot',
|
||||
'destination_type': 'volume',
|
||||
'delete_on_termination': True
|
||||
}],
|
||||
'block_device_mapping_v2': [
|
||||
{
|
||||
'boot_index': '0',
|
||||
'uuid': snapshotId,
|
||||
# 'volume_size': 1,
|
||||
# 'device_name': 'vda',
|
||||
'source_type': 'snapshot',
|
||||
'destination_type': 'volume',
|
||||
'delete_on_termination': True,
|
||||
}
|
||||
],
|
||||
'flavorRef': flavorId,
|
||||
# 'OS-DCF:diskConfig': 'AUTO',
|
||||
'max_count': count,
|
||||
'min_count': count,
|
||||
'networks': [{'uuid': networkId}],
|
||||
'security_groups': [{'name': sg} for sg in securityGroupsIdsList]
|
||||
'security_groups': [{'name': sg} for sg in securityGroupsIdsList],
|
||||
}
|
||||
}
|
||||
|
||||
r = requests.post(self._getEndpointFor('compute') + '/servers',
|
||||
data=json.dumps(data),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout)
|
||||
r = self._session.post(
|
||||
self._getEndpointFor('compute') + '/servers',
|
||||
data=json.dumps(data),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Cannot create instance from snapshot.')
|
||||
|
||||
@ -581,31 +638,35 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
|
||||
@authProjectRequired
|
||||
def deleteServer(self, serverId: str) -> None:
|
||||
# r = requests.post(
|
||||
# r = self._session.post(
|
||||
# self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
# data='{"forceDelete": null}',
|
||||
# headers=self._requestHeaders(),
|
||||
# verify=VERIFY_SSL,
|
||||
# timeout=self._timeout
|
||||
# )
|
||||
r = requests.delete(
|
||||
self._getEndpointFor('compute') + '/servers/{server_id}'.format(server_id=serverId),
|
||||
r = self._session.delete(
|
||||
self._getEndpointFor('compute')
|
||||
+ '/servers/{server_id}'.format(server_id=serverId),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Cannot delete server (probably server does not exists).')
|
||||
ensureResponseIsValid(
|
||||
r, 'Cannot delete server (probably server does not exists).'
|
||||
)
|
||||
|
||||
# This does not returns anything
|
||||
|
||||
@authProjectRequired
|
||||
def deleteSnapshot(self, snapshotId: str) -> None:
|
||||
r = requests.delete(
|
||||
self._getEndpointFor('volumev2') + '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
r = self._session.delete(
|
||||
self._getEndpointFor('volumev2')
|
||||
+ '/snapshots/{snapshot_id}'.format(snapshot_id=snapshotId),
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Cannot remove snapshot.')
|
||||
@ -614,12 +675,13 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
|
||||
@authProjectRequired
|
||||
def startServer(self, serverId: str) -> None:
|
||||
r = requests.post(
|
||||
self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
r = self._session.post(
|
||||
self._getEndpointFor('compute')
|
||||
+ '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"os-start": null}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Starting server')
|
||||
@ -628,48 +690,52 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
|
||||
@authProjectRequired
|
||||
def stopServer(self, serverId: str) -> None:
|
||||
r = requests.post(
|
||||
self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
r = self._session.post(
|
||||
self._getEndpointFor('compute')
|
||||
+ '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"os-stop": null}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Stoping server')
|
||||
|
||||
@authProjectRequired
|
||||
def suspendServer(self, serverId: str) -> None:
|
||||
r = requests.post(
|
||||
self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
r = self._session.post(
|
||||
self._getEndpointFor('compute')
|
||||
+ '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"suspend": null}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Suspending server')
|
||||
|
||||
@authProjectRequired
|
||||
def resumeServer(self, serverId: str) -> None:
|
||||
r = requests.post(
|
||||
self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
r = self._session.post(
|
||||
self._getEndpointFor('compute')
|
||||
+ '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"resume": null}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
ensureResponseIsValid(r, 'Resuming server')
|
||||
|
||||
@authProjectRequired
|
||||
def resetServer(self, serverId: str) -> None:
|
||||
r = requests.post( # pylint: disable=unused-variable
|
||||
self._getEndpointFor('compute') + '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
r = self._session.post( # pylint: disable=unused-variable
|
||||
self._getEndpointFor('compute')
|
||||
+ '/servers/{server_id}/action'.format(server_id=serverId),
|
||||
data='{"reboot":{"type":"HARD"}}',
|
||||
headers=self._requestHeaders(),
|
||||
verify=VERIFY_SSL,
|
||||
timeout=self._timeout
|
||||
timeout=self._timeout,
|
||||
)
|
||||
|
||||
# Ignore response for this...
|
||||
@ -679,10 +745,8 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
# First, ensure requested api is supported
|
||||
# We need api version 3.2 or greater
|
||||
try:
|
||||
r = requests.get(
|
||||
self._authUrl,
|
||||
verify=VERIFY_SSL,
|
||||
headers=self._requestHeaders()
|
||||
r = self._session.get(
|
||||
self._authUrl, verify=VERIFY_SSL, headers=self._requestHeaders()
|
||||
)
|
||||
except Exception:
|
||||
logger.exception('Testing')
|
||||
@ -702,4 +766,8 @@ class Client: # pylint: disable=too-many-public-methods
|
||||
# logger.exception('xx')
|
||||
raise Exception('Invalid endpoint (maybe invalid version selected?)')
|
||||
|
||||
raise Exception(_('Openstack does not support identity API 3.2 or newer. This OpenStack server is not compatible with UDS.'))
|
||||
raise Exception(
|
||||
_(
|
||||
'Openstack does not support identity API 3.2 or newer. This OpenStack server is not compatible with UDS.'
|
||||
)
|
||||
)
|
||||
|
@ -53,6 +53,7 @@ INTERFACE_VALUES: typing.List[gui.ChoiceType] = [
|
||||
gui.choiceItem('admin', 'admin'),
|
||||
]
|
||||
|
||||
|
||||
class OpenStackProvider(ServiceProvider):
|
||||
"""
|
||||
This class represents the sample services provider
|
||||
@ -70,6 +71,7 @@ class OpenStackProvider(ServiceProvider):
|
||||
we MUST register it at package __init__.
|
||||
|
||||
"""
|
||||
|
||||
# : What kind of services we offer, this are classes inherited from Service
|
||||
offers = [LiveService]
|
||||
# : Name to show the administrator. This string will be translated BEFORE
|
||||
@ -94,23 +96,122 @@ class OpenStackProvider(ServiceProvider):
|
||||
# but used for sample purposes
|
||||
# If we don't indicate an order, the output order of fields will be
|
||||
# "random"
|
||||
endpoint = gui.TextField(length=128, label=_('Identity endpoint'), order=1, tooltip=_('OpenStack identity endpoint API Access (for example, https://10.0.0.0/identity)'), required=True)
|
||||
endpoint = gui.TextField(
|
||||
length=128,
|
||||
label=_('Identity endpoint'),
|
||||
order=1,
|
||||
tooltip=_(
|
||||
'OpenStack identity endpoint API Access (for example, https://10.0.0.1/identity). Do not include /v3.'
|
||||
),
|
||||
required=True,
|
||||
)
|
||||
|
||||
access = gui.ChoiceField(label=_('Access interface'), order=5, tooltip=_('Access interface to be used'), values=INTERFACE_VALUES, defvalue='public')
|
||||
access = gui.ChoiceField(
|
||||
label=_('Access interface'),
|
||||
order=5,
|
||||
tooltip=_('Access interface to be used'),
|
||||
values=INTERFACE_VALUES,
|
||||
defvalue='public',
|
||||
)
|
||||
|
||||
domain = gui.TextField(length=64, label=_('Domain'), order=8, tooltip=_('Domain name (default is Default)'), required=True, defvalue='Default')
|
||||
username = gui.TextField(length=64, label=_('Username'), order=9, tooltip=_('User with valid privileges on OpenStack'), required=True, defvalue='admin')
|
||||
password = gui.PasswordField(lenth=32, label=_('Password'), order=10, tooltip=_('Password of the user of OpenStack'), required=True)
|
||||
domain = gui.TextField(
|
||||
length=64,
|
||||
label=_('Domain'),
|
||||
order=8,
|
||||
tooltip=_('Domain name (default is Default)'),
|
||||
required=True,
|
||||
defvalue='Default',
|
||||
)
|
||||
username = gui.TextField(
|
||||
length=64,
|
||||
label=_('Username'),
|
||||
order=9,
|
||||
tooltip=_('User with valid privileges on OpenStack'),
|
||||
required=True,
|
||||
defvalue='admin',
|
||||
)
|
||||
password = gui.PasswordField(
|
||||
lenth=32,
|
||||
label=_('Password'),
|
||||
order=10,
|
||||
tooltip=_('Password of the user of OpenStack'),
|
||||
required=True,
|
||||
)
|
||||
|
||||
maxPreparingServices = gui.NumericField(length=3, label=_('Creation concurrency'), defvalue='10', minValue=1, maxValue=65536, order=50, tooltip=_('Maximum number of concurrently creating VMs'), required=True, tab=gui.ADVANCED_TAB)
|
||||
maxRemovingServices = gui.NumericField(length=3, label=_('Removal concurrency'), defvalue='5', minValue=1, maxValue=65536, order=51, tooltip=_('Maximum number of concurrently removing VMs'), required=True, tab=gui.ADVANCED_TAB)
|
||||
maxPreparingServices = gui.NumericField(
|
||||
length=3,
|
||||
label=_('Creation concurrency'),
|
||||
defvalue='10',
|
||||
minValue=1,
|
||||
maxValue=65536,
|
||||
order=50,
|
||||
tooltip=_('Maximum number of concurrently creating VMs'),
|
||||
required=True,
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
maxRemovingServices = gui.NumericField(
|
||||
length=3,
|
||||
label=_('Removal concurrency'),
|
||||
defvalue='5',
|
||||
minValue=1,
|
||||
maxValue=65536,
|
||||
order=51,
|
||||
tooltip=_('Maximum number of concurrently removing VMs'),
|
||||
required=True,
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
timeout = gui.NumericField(length=3, label=_('Timeout'), defvalue='10', minValue=1, maxValue=128, order=99, tooltip=_('Timeout in seconds of connection to OpenStack'), required=True, tab=gui.ADVANCED_TAB)
|
||||
timeout = gui.NumericField(
|
||||
length=3,
|
||||
label=_('Timeout'),
|
||||
defvalue='10',
|
||||
minValue=1,
|
||||
maxValue=128,
|
||||
order=99,
|
||||
tooltip=_('Timeout in seconds of connection to OpenStack'),
|
||||
required=True,
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
tenant = gui.TextField(length=64, label=_('Project Id'), order=6, tooltip=_('Project (tenant) for this provider. Set only if required by server.'), required=False, defvalue='', tab=gui.ADVANCED_TAB)
|
||||
region = gui.TextField(length=64, label=_('Region'), order=7, tooltip=_('Region for this provider. Set only if required by server.'), required=False, defvalue='', tab=gui.ADVANCED_TAB)
|
||||
|
||||
useSubnetsName = gui.CheckBoxField(label=_('Subnets names'), order=8, tooltip=_('If checked, the name of the subnets will be used instead of the names of networks'), defvalue=gui.FALSE, tab=gui.ADVANCED_TAB)
|
||||
tenant = gui.TextField(
|
||||
length=64,
|
||||
label=_('Project Id'),
|
||||
order=6,
|
||||
tooltip=_(
|
||||
'Project (tenant) for this provider. Set only if required by server.'
|
||||
),
|
||||
required=False,
|
||||
defvalue='',
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
region = gui.TextField(
|
||||
length=64,
|
||||
label=_('Region'),
|
||||
order=7,
|
||||
tooltip=_('Region for this provider. Set only if required by server.'),
|
||||
required=False,
|
||||
defvalue='',
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
useSubnetsName = gui.CheckBoxField(
|
||||
label=_('Subnets names'),
|
||||
order=8,
|
||||
tooltip=_(
|
||||
'If checked, the name of the subnets will be used instead of the names of networks'
|
||||
),
|
||||
defvalue=gui.FALSE,
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
httpsProxy = gui.TextField(
|
||||
length=96,
|
||||
label=_('Proxy'),
|
||||
order=91,
|
||||
tooltip=_('Proxy used for connection to azure for HTTPS connections (use PROTOCOL://host:port, i.e. http://10.10.0.1:8080)'),
|
||||
required=False,
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
legacy = False
|
||||
|
||||
@ -130,6 +231,11 @@ class OpenStackProvider(ServiceProvider):
|
||||
projectId = projectId or self.tenant.value or None
|
||||
region = region or self.region.value or None
|
||||
if self._api is None:
|
||||
proxies = None
|
||||
if self.httpsProxy.value.strip():
|
||||
proxies = {
|
||||
'https': self.httpsProxy.value
|
||||
}
|
||||
self._api = openstack.Client(
|
||||
self.endpoint.value,
|
||||
-1,
|
||||
@ -140,7 +246,8 @@ class OpenStackProvider(ServiceProvider):
|
||||
useSSL=False,
|
||||
projectId=projectId,
|
||||
region=region,
|
||||
access=self.access.value
|
||||
access=self.access.value,
|
||||
proxies=proxies
|
||||
)
|
||||
return self._api
|
||||
|
||||
|
@ -59,7 +59,7 @@ INTERFACE_VALUES = [
|
||||
|
||||
|
||||
class ProviderLegacy(ServiceProvider):
|
||||
'''
|
||||
"""
|
||||
This class represents the sample services provider
|
||||
|
||||
In this class we provide:
|
||||
@ -74,7 +74,8 @@ class ProviderLegacy(ServiceProvider):
|
||||
For this class to get visible at administration client as a provider type,
|
||||
we MUST register it at package __init__.
|
||||
|
||||
'''
|
||||
"""
|
||||
|
||||
# : What kind of services we offer, this are classes inherited from Service
|
||||
offers = [LiveService]
|
||||
# : Name to show the administrator. This string will be translated BEFORE
|
||||
@ -84,7 +85,9 @@ class ProviderLegacy(ServiceProvider):
|
||||
# : Type used internally to identify this provider
|
||||
typeType = 'openStackPlatform'
|
||||
# : Description shown at administration interface for this provider
|
||||
typeDescription = _('OpenStack LEGACY platform service provider (for older Openstack Releases, previous to OCATA)')
|
||||
typeDescription = _(
|
||||
'OpenStack LEGACY platform service provider (for older Openstack Releases, previous to OCATA)'
|
||||
)
|
||||
# : Icon file used as icon for this provider. This string will be translated
|
||||
# : BEFORE sending it to administration interface, so don't forget to
|
||||
# : mark it as _ (using ugettext_noop)
|
||||
@ -99,20 +102,102 @@ class ProviderLegacy(ServiceProvider):
|
||||
# but used for sample purposes
|
||||
# If we don't indicate an order, the output order of fields will be
|
||||
# "random"
|
||||
host = gui.TextField(length=64, label=_('Host'), order=1, tooltip=_('OpenStack Host'), required=True)
|
||||
port = gui.NumericField(length=5, label=_('Port'), defvalue='5000', order=2, tooltip=_('5000 for older releases, 80/443 (ssl) for releases newer than OCATA'), required=True)
|
||||
ssl = gui.CheckBoxField(label=_('Use SSL'), order=4, tooltip=_('If checked, the connection will be forced to be ssl (will not work if server is not providing ssl)'))
|
||||
host = gui.TextField(
|
||||
length=64, label=_('Host'), order=1, tooltip=_('OpenStack Host'), required=True
|
||||
)
|
||||
port = gui.NumericField(
|
||||
length=5,
|
||||
label=_('Port'),
|
||||
defvalue='5000',
|
||||
order=2,
|
||||
tooltip=_(
|
||||
'5000 for older releases, 80/443 (ssl) for releases newer than OCATA'
|
||||
),
|
||||
required=True,
|
||||
)
|
||||
ssl = gui.CheckBoxField(
|
||||
label=_('Use SSL'),
|
||||
order=4,
|
||||
tooltip=_(
|
||||
'If checked, the connection will be forced to be ssl (will not work if server is not providing ssl)'
|
||||
),
|
||||
)
|
||||
|
||||
access = gui.ChoiceField(label=_('Access interface'), order=5, tooltip=_('Access interface to be used'), values=INTERFACE_VALUES, defvalue='public')
|
||||
access = gui.ChoiceField(
|
||||
label=_('Access interface'),
|
||||
order=5,
|
||||
tooltip=_('Access interface to be used'),
|
||||
values=INTERFACE_VALUES,
|
||||
defvalue='public',
|
||||
)
|
||||
|
||||
domain = gui.TextField(length=64, label=_('Domain'), order=8, tooltip=_('Domain name (default is Default)'), required=True, defvalue='Default')
|
||||
username = gui.TextField(length=64, label=_('Username'), order=9, tooltip=_('User with valid privileges on OpenStack'), required=True, defvalue='admin')
|
||||
password = gui.PasswordField(lenth=32, label=_('Password'), order=10, tooltip=_('Password of the user of OpenStack'), required=True)
|
||||
domain = gui.TextField(
|
||||
length=64,
|
||||
label=_('Domain'),
|
||||
order=8,
|
||||
tooltip=_('Domain name (default is Default)'),
|
||||
required=True,
|
||||
defvalue='Default',
|
||||
)
|
||||
username = gui.TextField(
|
||||
length=64,
|
||||
label=_('Username'),
|
||||
order=9,
|
||||
tooltip=_('User with valid privileges on OpenStack'),
|
||||
required=True,
|
||||
defvalue='admin',
|
||||
)
|
||||
password = gui.PasswordField(
|
||||
lenth=32,
|
||||
label=_('Password'),
|
||||
order=10,
|
||||
tooltip=_('Password of the user of OpenStack'),
|
||||
required=True,
|
||||
)
|
||||
|
||||
maxPreparingServices = gui.NumericField(length=3, label=_('Creation concurrency'), defvalue='10', minValue=1, maxValue=65536, order=50, tooltip=_('Maximum number of concurrently creating VMs'), required=True, tab=gui.ADVANCED_TAB)
|
||||
maxRemovingServices = gui.NumericField(length=3, label=_('Removal concurrency'), defvalue='5', minValue=1, maxValue=65536, order=51, tooltip=_('Maximum number of concurrently removing VMs'), required=True, tab=gui.ADVANCED_TAB)
|
||||
maxPreparingServices = gui.NumericField(
|
||||
length=3,
|
||||
label=_('Creation concurrency'),
|
||||
defvalue='10',
|
||||
minValue=1,
|
||||
maxValue=65536,
|
||||
order=50,
|
||||
tooltip=_('Maximum number of concurrently creating VMs'),
|
||||
required=True,
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
maxRemovingServices = gui.NumericField(
|
||||
length=3,
|
||||
label=_('Removal concurrency'),
|
||||
defvalue='5',
|
||||
minValue=1,
|
||||
maxValue=65536,
|
||||
order=51,
|
||||
tooltip=_('Maximum number of concurrently removing VMs'),
|
||||
required=True,
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
timeout = gui.NumericField(length=3, label=_('Timeout'), defvalue='10', minValue=1, maxValue=128, order=99, tooltip=_('Timeout in seconds of connection to OpenStack'), required=True, tab=gui.ADVANCED_TAB)
|
||||
timeout = gui.NumericField(
|
||||
length=3,
|
||||
label=_('Timeout'),
|
||||
defvalue='10',
|
||||
minValue=1,
|
||||
maxValue=128,
|
||||
order=99,
|
||||
tooltip=_('Timeout in seconds of connection to OpenStack'),
|
||||
required=True,
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
httpsProxy = gui.TextField(
|
||||
length=96,
|
||||
label=_('Proxy'),
|
||||
order=91,
|
||||
tooltip=_('Proxy used for connection to azure for HTTPS connections (use PROTOCOL://host:port, i.e. http://10.10.0.1:8080)'),
|
||||
required=False,
|
||||
tab=gui.ADVANCED_TAB,
|
||||
)
|
||||
|
||||
# tenant = gui.TextField(length=64, label=_('Project'), order=6, tooltip=_('Project (tenant) for this provider'), required=True, defvalue='')
|
||||
# region = gui.TextField(length=64, label=_('Region'), order=7, tooltip=_('Region for this provider'), required=True, defvalue='RegionOne')
|
||||
@ -123,15 +208,18 @@ class ProviderLegacy(ServiceProvider):
|
||||
_api: typing.Optional[openstack.Client] = None
|
||||
|
||||
def initialize(self, values: 'Module.ValuesType' = None):
|
||||
'''
|
||||
"""
|
||||
We will use the "autosave" feature for form fields
|
||||
'''
|
||||
"""
|
||||
# Just reset _api connection variable
|
||||
|
||||
if values is not None:
|
||||
self.timeout.value = validators.validateTimeout(self.timeout.value)
|
||||
|
||||
def api(self, projectId=None, region=None) -> openstack.Client:
|
||||
proxies = None
|
||||
if self.httpsProxy.value.strip():
|
||||
proxies = {'https': self.httpsProxy.value}
|
||||
return openstack.Client(
|
||||
self.host.value,
|
||||
self.port.value,
|
||||
@ -142,20 +230,21 @@ class ProviderLegacy(ServiceProvider):
|
||||
useSSL=self.ssl.isTrue(),
|
||||
projectId=projectId,
|
||||
region=region,
|
||||
access=self.access.value
|
||||
access=self.access.value,
|
||||
proxies=proxies,
|
||||
)
|
||||
|
||||
def sanitizeVmName(self, name: str) -> str:
|
||||
return openstack.sanitizeName(name)
|
||||
|
||||
def testConnection(self):
|
||||
'''
|
||||
"""
|
||||
Test that conection to OpenStack server is fine
|
||||
|
||||
Returns
|
||||
|
||||
True if all went fine, false if id didn't
|
||||
'''
|
||||
"""
|
||||
|
||||
try:
|
||||
if self.api().testConnection() is False:
|
||||
@ -167,7 +256,7 @@ class ProviderLegacy(ServiceProvider):
|
||||
|
||||
@staticmethod
|
||||
def test(env, data):
|
||||
'''
|
||||
"""
|
||||
Test ovirt Connectivity
|
||||
|
||||
Args:
|
||||
@ -181,5 +270,5 @@ class ProviderLegacy(ServiceProvider):
|
||||
(True is all right, false is error),
|
||||
second is an String with error, preferably internacionalizated..
|
||||
|
||||
'''
|
||||
"""
|
||||
return ProviderLegacy(env, data).testConnection()
|
||||
|
Loading…
Reference in New Issue
Block a user