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
214 version_client = HTTPClient("http://127.0.0.1:19393")
217 if field in VERSION_PARAMS:
218 fields[field] = kwargs[field]
220 msg = 'install() got an unexpected keyword argument \'%s\''
221 raise TypeError(msg % field)
224 hdrs = self._version_meta_to_headers(fields)
225 resp, body = version_client.post(url, headers=None, data=hdrs)
226 return Version(self, body)