1 # Copyright 2012 OpenStack Foundation
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
18 from oslo.utils import encodeutils
19 from oslo.utils import strutils
21 import six.moves.urllib.parse as urlparse
23 from escalatorclient.common import utils
24 from escalatorclient.openstack.common.apiclient import base
25 from escalatorclient.common.http import HTTPClient
27 CREATE_PARAMS = ('id', 'name', 'description', 'type', 'version', 'size',
28 'checksum', 'status', 'os_status', 'version_patch')
30 DEFAULT_PAGE_SIZE = 200
31 VERSION_PARAMS = ('type')
32 SORT_DIR_VALUES = ('asc', 'desc')
34 'name', 'id', 'cluster_id', 'created_at', 'updated_at', 'status')
36 OS_REQ_ID_HDR = 'x-openstack-request-id'
39 class Version(base.Resource):
42 return "<Version %s>" % self._info
44 def update(self, **fields):
45 self.manager.update(self, **fields)
47 def delete(self, **kwargs):
48 return self.manager.delete(self)
50 def data(self, **kwargs):
51 return self.manager.data(self, **kwargs)
54 class VersionManager(base.ManagerWithFind):
55 resource_class = Version
57 def get_version_client(self):
58 endpoint = "http://127.0.0.1:19292"
59 client = HTTPClient(endpoint)
62 def _list(self, url, response_key, obj_class=None, body=None):
63 version_client = self.get_version_client()
64 resp, body = version_client.get(url)
67 obj_class = self.resource_class
69 data = body[response_key]
70 return ([obj_class(self, res, loaded=True) for res in data if res],
73 def _version_meta_from_headers(self, headers):
74 meta = {'properties': {}}
75 safe_decode = encodeutils.safe_decode
76 for key, value in six.iteritems(headers):
77 value = safe_decode(value, incoming='utf-8')
78 if key.startswith('x-image-meta-property-'):
79 _key = safe_decode(key[22:], incoming='utf-8')
80 meta['properties'][_key] = value
81 elif key.startswith('x-image-meta-'):
82 _key = safe_decode(key[13:], incoming='utf-8')
85 for key in ['is_public', 'protected', 'deleted']:
87 meta[key] = strutils.bool_from_string(meta[key])
89 return self._format_version_meta_for_user(meta)
91 def _version_meta_to_headers(self, fields):
93 fields_copy = copy.deepcopy(fields)
94 for key, value in six.iteritems(fields_copy):
95 headers['%s' % key] = utils.to_str(value)
99 def _format_version_meta_for_user(meta):
100 for key in ['size', 'min_ram', 'min_disk']:
103 meta[key] = int(meta[key]) if meta[key] else 0
108 def _build_params(self, parameters):
109 params = {'limit': parameters.get('page_size', DEFAULT_PAGE_SIZE)}
111 if 'marker' in parameters:
112 params['marker'] = parameters['marker']
114 sort_key = parameters.get('sort_key')
115 if sort_key is not None:
116 if sort_key in SORT_KEY_VALUES:
117 params['sort_key'] = sort_key
119 raise ValueError('sort_key must be one of the following: %s.'
120 % ', '.join(SORT_KEY_VALUES))
122 sort_dir = parameters.get('sort_dir')
123 if sort_dir is not None:
124 if sort_dir in SORT_DIR_VALUES:
125 params['sort_dir'] = sort_dir
127 raise ValueError('sort_dir must be one of the following: %s.'
128 % ', '.join(SORT_DIR_VALUES))
130 filters = parameters.get('filters', {})
131 params.update(filters)
135 def list(self, **kwargs):
136 """Get a list of versions.
138 :param page_size: number of items to request in each paginated request
139 :param limit: maximum number of versions to return
140 :param marker:begin returning versions that appear later in version
141 list than that represented by this version id
142 :param filters: dict of direct comparison filters that mimics the
143 structure of an version object
144 :param return_request_id: If an empty list is provided, populate this
145 list with the request ID value from the header
146 x-openstack-request-id
147 :rtype: list of :class:`version`
149 absolute_limit = kwargs.get('limit')
150 page_size = kwargs.get('page_size', DEFAULT_PAGE_SIZE)
152 def paginate(qp, return_request_id=None):
153 for param, value in six.iteritems(qp):
154 if isinstance(value, six.string_types):
155 # Note(flaper87) Url encoding should
156 # be moved inside http utils, at least
159 # Making sure all params are str before
160 # trying to encode them
161 qp[param] = encodeutils.safe_decode(value)
163 url = '/v1/versions?%s' % urlparse.urlencode(qp)
164 versions, resp = self._list(url, "versions")
166 if return_request_id is not None:
167 return_request_id.append(resp.headers.get(OS_REQ_ID_HDR, None))
169 for version in versions:
172 return_request_id = kwargs.get('return_req_id', None)
174 params = self._build_params(kwargs)
180 for version in paginate(params, return_request_id):
181 last_version = version.id
183 if (absolute_limit is not None and
184 seen + seen_last_page >= absolute_limit):
185 # Note(kragniz): we've seen enough images
191 seen += seen_last_page
193 if seen_last_page + filtered == 0:
194 # Note(kragniz): we didn't get any versions in the last page
197 if absolute_limit is not None and seen >= absolute_limit:
198 # Note(kragniz): reached the limit of versions to return
201 if page_size and seen_last_page + filtered < page_size:
202 # Note(kragniz): we've reached the last page of the versions
205 # Note(kragniz): there are more versions to come
206 params['marker'] = last_version
209 def version(self, **kwargs):
210 """Get internal or external version of escalator.
212 TODO(bcwaldon): document accepted params
216 if field in VERSION_PARAMS:
217 fields[field] = kwargs[field]
219 msg = 'install() got an unexpected keyword argument \'%s\''
220 raise TypeError(msg % field)
223 hdrs = self._version_meta_to_headers(fields)
224 resp, body = self.client.post(url, headers=None, data=hdrs)
225 return Version(self, body)