Begin low-level API for Image v1 and v2
image list for v1 and v2: * Add --public|--private to command parsers * Implement local public/private filtering for v1 image_list() * Pass public/private filter to server for v2 image_list() Change-Id: Ie7c24ea2d1bf2b3b1b7fa342eb45fee45894634d
This commit is contained in:
		@@ -139,12 +139,21 @@ List available images
 | 
			
		||||
 | 
			
		||||
    os image list
 | 
			
		||||
        [--page-size <size>]
 | 
			
		||||
        [--public|--private]
 | 
			
		||||
        [--long]
 | 
			
		||||
 | 
			
		||||
.. option:: --page-size <size>
 | 
			
		||||
 | 
			
		||||
    Number of images to request in each paginated request
 | 
			
		||||
 | 
			
		||||
.. option:: --public
 | 
			
		||||
 | 
			
		||||
    List only public images
 | 
			
		||||
 | 
			
		||||
.. option:: --private
 | 
			
		||||
 | 
			
		||||
    List only private images
 | 
			
		||||
 | 
			
		||||
.. option:: --long
 | 
			
		||||
 | 
			
		||||
    List additional fields in output
 | 
			
		||||
 
 | 
			
		||||
@@ -161,7 +161,7 @@ class BaseAPI(KeystoneSession):
 | 
			
		||||
    ):
 | 
			
		||||
        """Return a list of resources
 | 
			
		||||
 | 
			
		||||
        GET ${ENDPOINT}/${PATH}
 | 
			
		||||
        GET ${ENDPOINT}/${PATH}?${PARAMS}
 | 
			
		||||
 | 
			
		||||
        path is often the object's plural resource type
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								openstackclient/api/image_v1.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								openstackclient/api/image_v1.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
#   Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
#   not use this file except in compliance with the License. You may obtain
 | 
			
		||||
#   a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
#   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
#   License for the specific language governing permissions and limitations
 | 
			
		||||
#   under the License.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
"""Image v1 API Library"""
 | 
			
		||||
 | 
			
		||||
from openstackclient.api import api
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class APIv1(api.BaseAPI):
 | 
			
		||||
    """Image v1 API"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, endpoint=None, **kwargs):
 | 
			
		||||
        super(APIv1, self).__init__(endpoint=endpoint, **kwargs)
 | 
			
		||||
 | 
			
		||||
        # Hack this until discovery is up
 | 
			
		||||
        self.endpoint = '/'.join([self.endpoint.rstrip('/'), 'v1'])
 | 
			
		||||
 | 
			
		||||
    def image_list(
 | 
			
		||||
        self,
 | 
			
		||||
        detailed=False,
 | 
			
		||||
        public=False,
 | 
			
		||||
        private=False,
 | 
			
		||||
        **filter
 | 
			
		||||
    ):
 | 
			
		||||
        """Get available images
 | 
			
		||||
 | 
			
		||||
        :param detailed:
 | 
			
		||||
            Retrieve detailed response from server if True
 | 
			
		||||
        :param public:
 | 
			
		||||
            Return public images if True
 | 
			
		||||
        :param private:
 | 
			
		||||
            Return private images if True
 | 
			
		||||
 | 
			
		||||
        If public and private are both True or both False then all images are
 | 
			
		||||
        returned.  Both arguments False is equivalent to no filter and all
 | 
			
		||||
        images are returned.  Both arguments True is a filter that includes
 | 
			
		||||
        both public and private images which is the same set as all images.
 | 
			
		||||
 | 
			
		||||
        http://docs.openstack.org/api/openstack-image-service/1.1/content/requesting-a-list-of-public-vm-images.html
 | 
			
		||||
        http://docs.openstack.org/api/openstack-image-service/1.1/content/requesting-detailed-metadata-on-public-vm-images.html
 | 
			
		||||
        http://docs.openstack.org/api/openstack-image-service/1.1/content/filtering-images-returned-via-get-images-and-get-imagesdetail.html
 | 
			
		||||
 | 
			
		||||
        TODO(dtroyer): Implement filtering
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        url = "/images"
 | 
			
		||||
        if detailed or public or private:
 | 
			
		||||
            # Because we can't all use /details
 | 
			
		||||
            url += "/detail"
 | 
			
		||||
 | 
			
		||||
        image_list = self.list(url, **filter)['images']
 | 
			
		||||
 | 
			
		||||
        if public != private:
 | 
			
		||||
            # One is True and one is False, so public represents the filter
 | 
			
		||||
            # state in either case
 | 
			
		||||
            image_list = [i for i in image_list if i['is_public'] == public]
 | 
			
		||||
 | 
			
		||||
        return image_list
 | 
			
		||||
							
								
								
									
										69
									
								
								openstackclient/api/image_v2.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								openstackclient/api/image_v2.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
#   Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
#   not use this file except in compliance with the License. You may obtain
 | 
			
		||||
#   a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
#   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
#   License for the specific language governing permissions and limitations
 | 
			
		||||
#   under the License.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
"""Image v2 API Library"""
 | 
			
		||||
 | 
			
		||||
from openstackclient.api import image_v1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class APIv2(image_v1.APIv1):
 | 
			
		||||
    """Image v2 API"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, endpoint=None, **kwargs):
 | 
			
		||||
        super(APIv2, self).__init__(endpoint=endpoint, **kwargs)
 | 
			
		||||
 | 
			
		||||
        # Hack this until discovery is up, and ignore parent endpoint setting
 | 
			
		||||
        self.endpoint = '/'.join([endpoint.rstrip('/'), 'v2'])
 | 
			
		||||
 | 
			
		||||
    def image_list(
 | 
			
		||||
        self,
 | 
			
		||||
        detailed=False,
 | 
			
		||||
        public=False,
 | 
			
		||||
        private=False,
 | 
			
		||||
        **filter
 | 
			
		||||
    ):
 | 
			
		||||
        """Get available images
 | 
			
		||||
 | 
			
		||||
        can add limit/marker
 | 
			
		||||
 | 
			
		||||
        :param detailed:
 | 
			
		||||
            For v1 compatibility only, ignored as v2 is always 'detailed'
 | 
			
		||||
        :param public:
 | 
			
		||||
            Return public images if True
 | 
			
		||||
        :param private:
 | 
			
		||||
            Return private images if True
 | 
			
		||||
 | 
			
		||||
        If public and private are both True or both False then all images are
 | 
			
		||||
        returned.  Both arguments False is equivalent to no filter and all
 | 
			
		||||
        images are returned.  Both arguments True is a filter that includes
 | 
			
		||||
        both public and private images which is the same set as all images.
 | 
			
		||||
 | 
			
		||||
        http://docs.openstack.org/api/openstack-image-service/2.0/content/list-images.html
 | 
			
		||||
 | 
			
		||||
        TODO(dtroyer): Implement filtering
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        if public == private:
 | 
			
		||||
            # No filtering for both False and both True cases
 | 
			
		||||
            filter.pop('visibility', None)
 | 
			
		||||
        elif public:
 | 
			
		||||
            filter['visibility'] = 'public'
 | 
			
		||||
        elif private:
 | 
			
		||||
            filter['visibility'] = 'private'
 | 
			
		||||
 | 
			
		||||
        url = "/images"
 | 
			
		||||
        if detailed:
 | 
			
		||||
            # Because we can't all use /details
 | 
			
		||||
            url += "/detail"
 | 
			
		||||
 | 
			
		||||
        return self.list(url, **filter)['images']
 | 
			
		||||
@@ -31,9 +31,15 @@ API_VERSIONS = {
 | 
			
		||||
    "2": "glanceclient.v2.client.Client",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IMAGE_API_TYPE = 'image'
 | 
			
		||||
IMAGE_API_VERSIONS = {
 | 
			
		||||
    '1': 'openstackclient.api.image_v1.APIv1',
 | 
			
		||||
    '2': 'openstackclient.api.image_v2.APIv2',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def make_client(instance):
 | 
			
		||||
    """Returns an image service client."""
 | 
			
		||||
    """Returns an image service client"""
 | 
			
		||||
    image_client = utils.get_client_class(
 | 
			
		||||
        API_NAME,
 | 
			
		||||
        instance._api_version[API_NAME],
 | 
			
		||||
@@ -45,13 +51,31 @@ def make_client(instance):
 | 
			
		||||
        region_name=instance._region_name,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    return image_client(
 | 
			
		||||
    client = image_client(
 | 
			
		||||
        endpoint,
 | 
			
		||||
        token=instance.auth.get_token(instance.session),
 | 
			
		||||
        cacert=instance._cacert,
 | 
			
		||||
        insecure=instance._insecure,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Create the low-level API
 | 
			
		||||
 | 
			
		||||
    image_api = utils.get_client_class(
 | 
			
		||||
        API_NAME,
 | 
			
		||||
        instance._api_version[API_NAME],
 | 
			
		||||
        IMAGE_API_VERSIONS)
 | 
			
		||||
    LOG.debug('Instantiating image api: %s', image_api)
 | 
			
		||||
 | 
			
		||||
    client.api = image_api(
 | 
			
		||||
        session=instance.session,
 | 
			
		||||
        endpoint=instance.get_endpoint_for_service_type(
 | 
			
		||||
            IMAGE_API_TYPE,
 | 
			
		||||
            region_name=instance._region_name,
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    return client
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def build_option_parser(parser):
 | 
			
		||||
    """Hook to add global options"""
 | 
			
		||||
 
 | 
			
		||||
@@ -300,6 +300,21 @@ class ListImage(lister.Lister):
 | 
			
		||||
            metavar="<size>",
 | 
			
		||||
            help="Number of images to request in each paginated request",
 | 
			
		||||
        )
 | 
			
		||||
        public_group = parser.add_mutually_exclusive_group()
 | 
			
		||||
        public_group.add_argument(
 | 
			
		||||
            "--public",
 | 
			
		||||
            dest="public",
 | 
			
		||||
            action="store_true",
 | 
			
		||||
            default=False,
 | 
			
		||||
            help="List only public images",
 | 
			
		||||
        )
 | 
			
		||||
        public_group.add_argument(
 | 
			
		||||
            "--private",
 | 
			
		||||
            dest="private",
 | 
			
		||||
            action="store_true",
 | 
			
		||||
            default=False,
 | 
			
		||||
            help="List only private images",
 | 
			
		||||
        )
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--long',
 | 
			
		||||
            action='store_true',
 | 
			
		||||
@@ -316,15 +331,21 @@ class ListImage(lister.Lister):
 | 
			
		||||
        kwargs = {}
 | 
			
		||||
        if parsed_args.page_size is not None:
 | 
			
		||||
            kwargs["page_size"] = parsed_args.page_size
 | 
			
		||||
        if parsed_args.public:
 | 
			
		||||
            kwargs['public'] = True
 | 
			
		||||
        if parsed_args.private:
 | 
			
		||||
            kwargs['private'] = True
 | 
			
		||||
        kwargs['detailed'] = parsed_args.long
 | 
			
		||||
 | 
			
		||||
        data = image_client.images.list(**kwargs)
 | 
			
		||||
        if parsed_args.long:
 | 
			
		||||
            columns = ('ID', 'Name', 'Disk Format', 'Container Format',
 | 
			
		||||
                       'Size', 'Status')
 | 
			
		||||
        else:
 | 
			
		||||
            columns = ("ID", "Name")
 | 
			
		||||
 | 
			
		||||
        return (columns, (utils.get_item_properties(s, columns) for s in data))
 | 
			
		||||
        data = image_client.api.image_list(**kwargs)
 | 
			
		||||
 | 
			
		||||
        return (columns, (utils.get_dict_properties(s, columns) for s in data))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SaveImage(command.Command):
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,21 @@ class ListImage(lister.Lister):
 | 
			
		||||
            metavar="<size>",
 | 
			
		||||
            help="Number of images to request in each paginated request",
 | 
			
		||||
        )
 | 
			
		||||
        public_group = parser.add_mutually_exclusive_group()
 | 
			
		||||
        public_group.add_argument(
 | 
			
		||||
            "--public",
 | 
			
		||||
            dest="public",
 | 
			
		||||
            action="store_true",
 | 
			
		||||
            default=False,
 | 
			
		||||
            help="List only public images",
 | 
			
		||||
        )
 | 
			
		||||
        public_group.add_argument(
 | 
			
		||||
            "--private",
 | 
			
		||||
            dest="private",
 | 
			
		||||
            action="store_true",
 | 
			
		||||
            default=False,
 | 
			
		||||
            help="List only private images",
 | 
			
		||||
        )
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--long',
 | 
			
		||||
            action='store_true',
 | 
			
		||||
@@ -81,15 +96,21 @@ class ListImage(lister.Lister):
 | 
			
		||||
        kwargs = {}
 | 
			
		||||
        if parsed_args.page_size is not None:
 | 
			
		||||
            kwargs["page_size"] = parsed_args.page_size
 | 
			
		||||
        if parsed_args.public:
 | 
			
		||||
            kwargs['public'] = True
 | 
			
		||||
        if parsed_args.private:
 | 
			
		||||
            kwargs['private'] = True
 | 
			
		||||
        kwargs['detailed'] = parsed_args.long
 | 
			
		||||
 | 
			
		||||
        data = image_client.images.list(**kwargs)
 | 
			
		||||
        if parsed_args.long:
 | 
			
		||||
            columns = ('ID', 'Name', 'Disk Format', 'Container Format',
 | 
			
		||||
                       'Size', 'Status')
 | 
			
		||||
        else:
 | 
			
		||||
            columns = ("ID", "Name")
 | 
			
		||||
 | 
			
		||||
        return (columns, (utils.get_item_properties(s, columns) for s in data))
 | 
			
		||||
        data = image_client.api.image_list(**kwargs)
 | 
			
		||||
 | 
			
		||||
        return (columns, (utils.get_dict_properties(s, columns) for s in data))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SaveImage(command.Command):
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										98
									
								
								openstackclient/tests/api/test_image_v1.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								openstackclient/tests/api/test_image_v1.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
#   Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
#   not use this file except in compliance with the License. You may obtain
 | 
			
		||||
#   a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
#   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
#   License for the specific language governing permissions and limitations
 | 
			
		||||
#   under the License.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
"""Image v1 API Library Tests"""
 | 
			
		||||
 | 
			
		||||
from requests_mock.contrib import fixture
 | 
			
		||||
 | 
			
		||||
from keystoneclient import session
 | 
			
		||||
from openstackclient.api import image_v1
 | 
			
		||||
from openstackclient.tests import utils
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
FAKE_PROJECT = 'xyzpdq'
 | 
			
		||||
FAKE_URL = 'http://gopher.com'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestImageAPIv1(utils.TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(TestImageAPIv1, self).setUp()
 | 
			
		||||
 | 
			
		||||
        sess = session.Session()
 | 
			
		||||
        self.api = image_v1.APIv1(session=sess, endpoint=FAKE_URL)
 | 
			
		||||
        self.requests_mock = self.useFixture(fixture.Fixture())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestImage(TestImageAPIv1):
 | 
			
		||||
 | 
			
		||||
    PUB_PROT = {
 | 
			
		||||
        'id': '1',
 | 
			
		||||
        'name': 'pub1',
 | 
			
		||||
        'is_public': True,
 | 
			
		||||
        'protected': True,
 | 
			
		||||
    }
 | 
			
		||||
    PUB_NOPROT = {
 | 
			
		||||
        'id': '2',
 | 
			
		||||
        'name': 'pub2-noprot',
 | 
			
		||||
        'is_public': True,
 | 
			
		||||
        'protected': False,
 | 
			
		||||
    }
 | 
			
		||||
    NOPUB_PROT = {
 | 
			
		||||
        'id': '3',
 | 
			
		||||
        'name': 'priv3',
 | 
			
		||||
        'is_public': False,
 | 
			
		||||
        'protected': True,
 | 
			
		||||
    }
 | 
			
		||||
    NOPUB_NOPROT = {
 | 
			
		||||
        'id': '4',
 | 
			
		||||
        'name': 'priv4-noprot',
 | 
			
		||||
        'is_public': False,
 | 
			
		||||
        'protected': False,
 | 
			
		||||
    }
 | 
			
		||||
    LIST_IMAGE_RESP = [
 | 
			
		||||
        PUB_PROT,
 | 
			
		||||
        PUB_NOPROT,
 | 
			
		||||
        NOPUB_PROT,
 | 
			
		||||
        NOPUB_NOPROT,
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def test_image_list_no_options(self):
 | 
			
		||||
        self.requests_mock.register_uri(
 | 
			
		||||
            'GET',
 | 
			
		||||
            FAKE_URL + '/v1/images',
 | 
			
		||||
            json={'images': self.LIST_IMAGE_RESP},
 | 
			
		||||
            status_code=200,
 | 
			
		||||
        )
 | 
			
		||||
        ret = self.api.image_list()
 | 
			
		||||
        self.assertEqual(self.LIST_IMAGE_RESP, ret)
 | 
			
		||||
 | 
			
		||||
    def test_image_list_public(self):
 | 
			
		||||
        self.requests_mock.register_uri(
 | 
			
		||||
            'GET',
 | 
			
		||||
            FAKE_URL + '/v1/images/detail',
 | 
			
		||||
            json={'images': self.LIST_IMAGE_RESP},
 | 
			
		||||
            status_code=200,
 | 
			
		||||
        )
 | 
			
		||||
        ret = self.api.image_list(public=True)
 | 
			
		||||
        self.assertEqual([self.PUB_PROT, self.PUB_NOPROT], ret)
 | 
			
		||||
 | 
			
		||||
    def test_image_list_private(self):
 | 
			
		||||
        self.requests_mock.register_uri(
 | 
			
		||||
            'GET',
 | 
			
		||||
            FAKE_URL + '/v1/images/detail',
 | 
			
		||||
            json={'images': self.LIST_IMAGE_RESP},
 | 
			
		||||
            status_code=200,
 | 
			
		||||
        )
 | 
			
		||||
        ret = self.api.image_list(private=True)
 | 
			
		||||
        self.assertEqual([self.NOPUB_PROT, self.NOPUB_NOPROT], ret)
 | 
			
		||||
							
								
								
									
										98
									
								
								openstackclient/tests/api/test_image_v2.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								openstackclient/tests/api/test_image_v2.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
#   Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
			
		||||
#   not use this file except in compliance with the License. You may obtain
 | 
			
		||||
#   a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
#   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
#   License for the specific language governing permissions and limitations
 | 
			
		||||
#   under the License.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
"""Image v2 API Library Tests"""
 | 
			
		||||
 | 
			
		||||
from requests_mock.contrib import fixture
 | 
			
		||||
 | 
			
		||||
from keystoneclient import session
 | 
			
		||||
from openstackclient.api import image_v2
 | 
			
		||||
from openstackclient.tests import utils
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
FAKE_PROJECT = 'xyzpdq'
 | 
			
		||||
FAKE_URL = 'http://gopher.com'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestImageAPIv2(utils.TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(TestImageAPIv2, self).setUp()
 | 
			
		||||
 | 
			
		||||
        sess = session.Session()
 | 
			
		||||
        self.api = image_v2.APIv2(session=sess, endpoint=FAKE_URL)
 | 
			
		||||
        self.requests_mock = self.useFixture(fixture.Fixture())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestImage(TestImageAPIv2):
 | 
			
		||||
 | 
			
		||||
    PUB_PROT = {
 | 
			
		||||
        'id': '1',
 | 
			
		||||
        'name': 'pub1',
 | 
			
		||||
        'visibility': 'public',
 | 
			
		||||
        'protected': True,
 | 
			
		||||
    }
 | 
			
		||||
    PUB_NOPROT = {
 | 
			
		||||
        'id': '2',
 | 
			
		||||
        'name': 'pub2-noprot',
 | 
			
		||||
        'visibility': 'public',
 | 
			
		||||
        'protected': False,
 | 
			
		||||
    }
 | 
			
		||||
    NOPUB_PROT = {
 | 
			
		||||
        'id': '3',
 | 
			
		||||
        'name': 'priv3',
 | 
			
		||||
        'visibility': 'private',
 | 
			
		||||
        'protected': True,
 | 
			
		||||
    }
 | 
			
		||||
    NOPUB_NOPROT = {
 | 
			
		||||
        'id': '4',
 | 
			
		||||
        'name': 'priv4-noprot',
 | 
			
		||||
        'visibility': 'private',
 | 
			
		||||
        'protected': False,
 | 
			
		||||
    }
 | 
			
		||||
    LIST_IMAGE_RESP = [
 | 
			
		||||
        PUB_PROT,
 | 
			
		||||
        PUB_NOPROT,
 | 
			
		||||
        NOPUB_PROT,
 | 
			
		||||
        NOPUB_NOPROT,
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def test_image_list_no_options(self):
 | 
			
		||||
        self.requests_mock.register_uri(
 | 
			
		||||
            'GET',
 | 
			
		||||
            FAKE_URL + '/v2/images',
 | 
			
		||||
            json={'images': self.LIST_IMAGE_RESP},
 | 
			
		||||
            status_code=200,
 | 
			
		||||
        )
 | 
			
		||||
        ret = self.api.image_list()
 | 
			
		||||
        self.assertEqual(self.LIST_IMAGE_RESP, ret)
 | 
			
		||||
 | 
			
		||||
    def test_image_list_public(self):
 | 
			
		||||
        self.requests_mock.register_uri(
 | 
			
		||||
            'GET',
 | 
			
		||||
            FAKE_URL + '/v2/images',
 | 
			
		||||
            json={'images': [self.PUB_PROT, self.PUB_NOPROT]},
 | 
			
		||||
            status_code=200,
 | 
			
		||||
        )
 | 
			
		||||
        ret = self.api.image_list(public=True)
 | 
			
		||||
        self.assertEqual([self.PUB_PROT, self.PUB_NOPROT], ret)
 | 
			
		||||
 | 
			
		||||
    def test_image_list_private(self):
 | 
			
		||||
        self.requests_mock.register_uri(
 | 
			
		||||
            'GET',
 | 
			
		||||
            FAKE_URL + '/v2/images',
 | 
			
		||||
            json={'images': [self.NOPUB_PROT, self.NOPUB_NOPROT]},
 | 
			
		||||
            status_code=200,
 | 
			
		||||
        )
 | 
			
		||||
        ret = self.api.image_list(public=True)
 | 
			
		||||
        self.assertEqual([self.NOPUB_PROT, self.NOPUB_NOPROT], ret)
 | 
			
		||||
@@ -300,6 +300,128 @@ class TestImageDelete(TestImage):
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestImageList(TestImage):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(TestImageList, self).setUp()
 | 
			
		||||
 | 
			
		||||
        self.api_mock = mock.Mock()
 | 
			
		||||
        self.api_mock.image_list.return_value = [
 | 
			
		||||
            copy.deepcopy(image_fakes.IMAGE),
 | 
			
		||||
        ]
 | 
			
		||||
        self.app.client_manager.image.api = self.api_mock
 | 
			
		||||
 | 
			
		||||
        # Get the command object to test
 | 
			
		||||
        self.cmd = image.ListImage(self.app, None)
 | 
			
		||||
 | 
			
		||||
    def test_image_list_no_options(self):
 | 
			
		||||
        arglist = []
 | 
			
		||||
        verifylist = [
 | 
			
		||||
            ('public', False),
 | 
			
		||||
            ('private', False),
 | 
			
		||||
            ('long', False),
 | 
			
		||||
        ]
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
			
		||||
 | 
			
		||||
        # DisplayCommandBase.take_action() returns two tuples
 | 
			
		||||
        columns, data = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.api_mock.image_list.assert_called_with(
 | 
			
		||||
            detailed=False,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        collist = ('ID', 'Name')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(columns, collist)
 | 
			
		||||
        datalist = ((
 | 
			
		||||
            image_fakes.image_id,
 | 
			
		||||
            image_fakes.image_name,
 | 
			
		||||
        ), )
 | 
			
		||||
        self.assertEqual(datalist, tuple(data))
 | 
			
		||||
 | 
			
		||||
    def test_image_list_public_option(self):
 | 
			
		||||
        arglist = [
 | 
			
		||||
            '--public',
 | 
			
		||||
        ]
 | 
			
		||||
        verifylist = [
 | 
			
		||||
            ('public', True),
 | 
			
		||||
            ('private', False),
 | 
			
		||||
            ('long', False),
 | 
			
		||||
        ]
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
			
		||||
 | 
			
		||||
        # DisplayCommandBase.take_action() returns two tuples
 | 
			
		||||
        columns, data = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.api_mock.image_list.assert_called_with(
 | 
			
		||||
            detailed=False,
 | 
			
		||||
            public=True,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        collist = ('ID', 'Name')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(columns, collist)
 | 
			
		||||
        datalist = ((
 | 
			
		||||
            image_fakes.image_id,
 | 
			
		||||
            image_fakes.image_name,
 | 
			
		||||
        ), )
 | 
			
		||||
        self.assertEqual(datalist, tuple(data))
 | 
			
		||||
 | 
			
		||||
    def test_image_list_private_option(self):
 | 
			
		||||
        arglist = [
 | 
			
		||||
            '--private',
 | 
			
		||||
        ]
 | 
			
		||||
        verifylist = [
 | 
			
		||||
            ('public', False),
 | 
			
		||||
            ('private', True),
 | 
			
		||||
            ('long', False),
 | 
			
		||||
        ]
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
			
		||||
 | 
			
		||||
        # DisplayCommandBase.take_action() returns two tuples
 | 
			
		||||
        columns, data = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.api_mock.image_list.assert_called_with(
 | 
			
		||||
            detailed=False,
 | 
			
		||||
            private=True,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        collist = ('ID', 'Name')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(columns, collist)
 | 
			
		||||
        datalist = ((
 | 
			
		||||
            image_fakes.image_id,
 | 
			
		||||
            image_fakes.image_name,
 | 
			
		||||
        ), )
 | 
			
		||||
        self.assertEqual(datalist, tuple(data))
 | 
			
		||||
 | 
			
		||||
    def test_image_list_long_option(self):
 | 
			
		||||
        arglist = [
 | 
			
		||||
            '--long',
 | 
			
		||||
        ]
 | 
			
		||||
        verifylist = [
 | 
			
		||||
            ('long', True),
 | 
			
		||||
        ]
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
			
		||||
 | 
			
		||||
        # DisplayCommandBase.take_action() returns two tuples
 | 
			
		||||
        columns, data = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.api_mock.image_list.assert_called_with(
 | 
			
		||||
            detailed=True,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        collist = ('ID', 'Name', 'Disk Format', 'Container Format',
 | 
			
		||||
                   'Size', 'Status')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(columns, collist)
 | 
			
		||||
        datalist = ((
 | 
			
		||||
            image_fakes.image_id,
 | 
			
		||||
            image_fakes.image_name,
 | 
			
		||||
            '',
 | 
			
		||||
            '',
 | 
			
		||||
            '',
 | 
			
		||||
            '',
 | 
			
		||||
        ), )
 | 
			
		||||
        self.assertEqual(datalist, tuple(data))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestImageSet(TestImage):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
@@ -453,48 +575,3 @@ class TestImageSet(TestImage):
 | 
			
		||||
            image_fakes.image_id,
 | 
			
		||||
            **kwargs
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestImageList(TestImage):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(TestImageList, self).setUp()
 | 
			
		||||
 | 
			
		||||
        # This is the return value for utils.find_resource()
 | 
			
		||||
        self.images_mock.list.return_value = [
 | 
			
		||||
            fakes.FakeResource(
 | 
			
		||||
                None,
 | 
			
		||||
                copy.deepcopy(image_fakes.IMAGE),
 | 
			
		||||
                loaded=True,
 | 
			
		||||
            ),
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        # Get the command object to test
 | 
			
		||||
        self.cmd = image.ListImage(self.app, None)
 | 
			
		||||
 | 
			
		||||
    def test_image_list_long_option(self):
 | 
			
		||||
        arglist = [
 | 
			
		||||
            '--long',
 | 
			
		||||
        ]
 | 
			
		||||
        verifylist = [
 | 
			
		||||
            ('long', True),
 | 
			
		||||
        ]
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
			
		||||
 | 
			
		||||
        # DisplayCommandBase.take_action() returns two tuples
 | 
			
		||||
        columns, data = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.images_mock.list.assert_called_with()
 | 
			
		||||
 | 
			
		||||
        collist = ('ID', 'Name', 'Disk Format', 'Container Format',
 | 
			
		||||
                   'Size', 'Status')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(columns, collist)
 | 
			
		||||
        datalist = ((
 | 
			
		||||
            image_fakes.image_id,
 | 
			
		||||
            image_fakes.image_name,
 | 
			
		||||
            '',
 | 
			
		||||
            '',
 | 
			
		||||
            '',
 | 
			
		||||
            '',
 | 
			
		||||
        ), )
 | 
			
		||||
        self.assertEqual(datalist, tuple(data))
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
import copy
 | 
			
		||||
import mock
 | 
			
		||||
 | 
			
		||||
from openstackclient.image.v2 import image
 | 
			
		||||
from openstackclient.tests import fakes
 | 
			
		||||
@@ -68,18 +69,93 @@ class TestImageList(TestImage):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        super(TestImageList, self).setUp()
 | 
			
		||||
 | 
			
		||||
        # This is the return value for utils.find_resource()
 | 
			
		||||
        self.images_mock.list.return_value = [
 | 
			
		||||
            fakes.FakeResource(
 | 
			
		||||
                None,
 | 
			
		||||
                copy.deepcopy(image_fakes.IMAGE),
 | 
			
		||||
                loaded=True,
 | 
			
		||||
            ),
 | 
			
		||||
        self.api_mock = mock.Mock()
 | 
			
		||||
        self.api_mock.image_list.return_value = [
 | 
			
		||||
            copy.deepcopy(image_fakes.IMAGE),
 | 
			
		||||
        ]
 | 
			
		||||
        self.app.client_manager.image.api = self.api_mock
 | 
			
		||||
 | 
			
		||||
        # Get the command object to test
 | 
			
		||||
        self.cmd = image.ListImage(self.app, None)
 | 
			
		||||
 | 
			
		||||
    def test_image_list_no_options(self):
 | 
			
		||||
        arglist = []
 | 
			
		||||
        verifylist = [
 | 
			
		||||
            ('public', False),
 | 
			
		||||
            ('private', False),
 | 
			
		||||
            ('long', False),
 | 
			
		||||
        ]
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
			
		||||
 | 
			
		||||
        # DisplayCommandBase.take_action() returns two tuples
 | 
			
		||||
        columns, data = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.api_mock.image_list.assert_called_with(
 | 
			
		||||
            detailed=False,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        collist = ('ID', 'Name')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(columns, collist)
 | 
			
		||||
        datalist = ((
 | 
			
		||||
            image_fakes.image_id,
 | 
			
		||||
            image_fakes.image_name,
 | 
			
		||||
        ), )
 | 
			
		||||
        self.assertEqual(datalist, tuple(data))
 | 
			
		||||
 | 
			
		||||
    def test_image_list_public_option(self):
 | 
			
		||||
        arglist = [
 | 
			
		||||
            '--public',
 | 
			
		||||
        ]
 | 
			
		||||
        verifylist = [
 | 
			
		||||
            ('public', True),
 | 
			
		||||
            ('private', False),
 | 
			
		||||
            ('long', False),
 | 
			
		||||
        ]
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
			
		||||
 | 
			
		||||
        # DisplayCommandBase.take_action() returns two tuples
 | 
			
		||||
        columns, data = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.api_mock.image_list.assert_called_with(
 | 
			
		||||
            detailed=False,
 | 
			
		||||
            public=True,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        collist = ('ID', 'Name')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(columns, collist)
 | 
			
		||||
        datalist = ((
 | 
			
		||||
            image_fakes.image_id,
 | 
			
		||||
            image_fakes.image_name,
 | 
			
		||||
        ), )
 | 
			
		||||
        self.assertEqual(datalist, tuple(data))
 | 
			
		||||
 | 
			
		||||
    def test_image_list_private_option(self):
 | 
			
		||||
        arglist = [
 | 
			
		||||
            '--private',
 | 
			
		||||
        ]
 | 
			
		||||
        verifylist = [
 | 
			
		||||
            ('public', False),
 | 
			
		||||
            ('private', True),
 | 
			
		||||
            ('long', False),
 | 
			
		||||
        ]
 | 
			
		||||
        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
 | 
			
		||||
 | 
			
		||||
        # DisplayCommandBase.take_action() returns two tuples
 | 
			
		||||
        columns, data = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.api_mock.image_list.assert_called_with(
 | 
			
		||||
            detailed=False,
 | 
			
		||||
            private=True,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        collist = ('ID', 'Name')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(columns, collist)
 | 
			
		||||
        datalist = ((
 | 
			
		||||
            image_fakes.image_id,
 | 
			
		||||
            image_fakes.image_name,
 | 
			
		||||
        ), )
 | 
			
		||||
        self.assertEqual(datalist, tuple(data))
 | 
			
		||||
 | 
			
		||||
    def test_image_list_long_option(self):
 | 
			
		||||
        arglist = [
 | 
			
		||||
            '--long',
 | 
			
		||||
@@ -91,7 +167,9 @@ class TestImageList(TestImage):
 | 
			
		||||
 | 
			
		||||
        # DisplayCommandBase.take_action() returns two tuples
 | 
			
		||||
        columns, data = self.cmd.take_action(parsed_args)
 | 
			
		||||
        self.images_mock.list.assert_called_with()
 | 
			
		||||
        self.api_mock.image_list.assert_called_with(
 | 
			
		||||
            detailed=True,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        collist = ('ID', 'Name', 'Disk Format', 'Container Format',
 | 
			
		||||
                   'Size', 'Status')
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user