Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added compatibility with operations project values #344

Merged
merged 2 commits into from
Jan 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion pylxd/models/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from pylxd import managers
from pylxd.exceptions import LXDAPIException
from pylxd.models import _model as model
from pylxd.models.operation import Operation

if six.PY2:
# Python2.7 doesn't have this natively
Expand Down Expand Up @@ -397,7 +398,8 @@ def execute(
})

fds = response.json()['metadata']['metadata']['fds']
operation_id = response.json()['operation'].split('/')[-1]
operation_id = \
Operation.extract_operation_id(response.json()['operation'])
parsed = parse.urlparse(
self.client.api.operations[operation_id].websocket._api_endpoint)

Expand Down
9 changes: 7 additions & 2 deletions pylxd/models/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
# under the License.

import warnings
import os

from pylxd import exceptions
from six.moves.urllib import parse


class Operation(object):
Expand All @@ -32,11 +34,14 @@ def wait_for_operation(cls, client, operation_id):
operation.wait()
return cls.get(client, operation.id)

@classmethod
def extract_operation_id(cls, s):
return os.path.split(parse.urlparse(s).path)[-1]

@classmethod
def get(cls, client, operation_id):
"""Get an operation."""
if operation_id.startswith('/'):
operation_id = operation_id.split('/')[-1]
operation_id = cls.extract_operation_id(operation_id)
response = client.api.operations[operation_id].get()
return cls(_client=client, **response.json()['metadata'])

Expand Down
38 changes: 21 additions & 17 deletions pylxd/tests/mock_lxd.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ def containers_POST(request, context):
context.status_code = 202
return json.dumps({
'type': 'async',
'operation': 'operation-abc'})
'operation': '/1.0/operations/operation-abc?project=default'})


def container_POST(request, context):
context.status_code = 202
if not request.json().get('migration', False):
return {
'type': 'async',
'operation': 'operation-abc'}
'operation': '/1.0/operations/operation-abc?project=default'}
else:
return {
'type': 'async',
'operation': 'operation-abc',
'operation': '/1.0/operations/operation-abc?project=default',
'metadata': {
'metadata': {
'0': 'abc',
Expand All @@ -32,21 +32,22 @@ def container_DELETE(request, context):
context.status_code = 202
return json.dumps({
'type': 'async',
'operation': 'operation-abc'})
'operation': '/1.0/operations/operation-abc?project=default'})


def images_POST(request, context):
context.status_code = 202
return json.dumps({
'type': 'async',
'operation': 'images-create-operation'})
'operation': '/1.0/operations/images-create-operation?project=default'
})


def image_DELETE(request, context):
context.status_code = 202
return json.dumps({
'type': 'async',
'operation': 'operation-abc'})
'operation': '/1.0/operations/operation-abc?project=default'})


def networks_GET(request, _):
Expand Down Expand Up @@ -80,7 +81,7 @@ def networks_DELETE(_, context):
context.status_code = 202
return json.dumps({
'type': 'sync',
'operation': 'operation-abc'})
'operation': '/1.0/operations/operation-abc?project=default'})


def profile_GET(request, context):
Expand Down Expand Up @@ -108,14 +109,14 @@ def profile_DELETE(request, context):
context.status_code = 200
return json.dumps({
'type': 'sync',
'operation': 'operation-abc'})
'operation': '/1.0/operations/operation-abc?project=default'})


def snapshot_DELETE(request, context):
context.status_code = 202
return json.dumps({
'type': 'async',
'operation': 'operation-abc'})
'operation': '/1.0/operations/operation-abc?project=default'})


RULES = [
Expand Down Expand Up @@ -439,7 +440,7 @@ def snapshot_DELETE(request, context):
'status_code': 202,
'json': {
'type': 'async',
'operation': 'operation-abc'},
'operation': '/1.0/operations/operation-abc?project=default'},
'method': 'PUT',
'url': r'^http://pylxd.test/1.0/containers/an-container/state$', # NOQA
},
Expand All @@ -451,7 +452,7 @@ def snapshot_DELETE(request, context):
{
'text': json.dumps({
'type': 'async',
'operation': 'operation-abc'}),
'operation': '/1.0/operations/operation-abc?project=default'}),
'status_code': 202,
'method': 'PUT',
'url': r'^http://pylxd.test/1.0/containers/an-container$',
Expand All @@ -474,7 +475,7 @@ def snapshot_DELETE(request, context):
}
},
},
'operation': 'operation-abc'},
'operation': '/1.0/operations/operation-abc?project=default'},
'status_code': 202,
'method': 'POST',
'url': r'^http://pylxd.test/1.0/containers/an-container/exec$', # NOQA
Expand All @@ -493,7 +494,7 @@ def snapshot_DELETE(request, context):
{
'text': json.dumps({
'type': 'async',
'operation': 'operation-abc'}),
'operation': '/1.0/operations/operation-abc?project=default'}),
'status_code': 202,
'method': 'POST',
'url': r'^http://pylxd.test/1.0/containers/an-container/snapshots$', # NOQA
Expand All @@ -511,7 +512,7 @@ def snapshot_DELETE(request, context):
{
'text': json.dumps({
'type': 'async',
'operation': 'operation-abc'}),
'operation': '/1.0/operations/operation-abc?project=default'}),
'status_code': 202,
'method': 'POST',
'url': r'^http://pylxd.test/1.0/containers/an-container/snapshots/an-snapshot$', # NOQA
Expand Down Expand Up @@ -636,7 +637,9 @@ def snapshot_DELETE(request, context):
'url': r'^http://pylxd2.test/1.0/images/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855$', # NOQA
},
{
'text': json.dumps({'type': 'async', 'operation': 'operation-abc'}),
'text': json.dumps({
'type': 'async',
'operation': '/1.0/operations/operation-abc?project=default'}),
'status_code': 202,
'method': 'PUT',
'url': r'^http://pylxd.test/1.0/images/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855$', # NOQA
Expand Down Expand Up @@ -865,7 +868,8 @@ def snapshot_DELETE(request, context):
},
# create an async storage volume
{
'json': {'type': 'async', 'operation': 'operation-abc'},
'json': {'type': 'async',
'operation': '/1.0/operations/operation-abc?project=default'},
'status_code': 202,
'method': 'POST',
'url': (r'^http://pylxd.test/1.0/storage-pools/'
Expand Down Expand Up @@ -909,7 +913,7 @@ def snapshot_DELETE(request, context):
{
'json': {
"type": "async",
"operation": "operation-abc",
"operation": "/1.0/operations/operation-abc?project=default",
"metadata": {
"control": "secret1",
"fs": "secret2"
Expand Down
8 changes: 8 additions & 0 deletions pylxd/tests/models/test_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ def test_get_full_path(self):

self.assertEqual('operation-abc', an_operation.id)

def test_get_full_path_and_project(self):
"""Return an operation even if the full path is specified."""
name = '/1.0/operations/operation-abc?project=default'

an_operation = models.Operation.get(self.client, name)

self.assertEqual('operation-abc', an_operation.id)

def test_wait_with_error(self):
"""If the operation errors, wait raises an exception."""
def error(request, context):
Expand Down