1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 '''
17 Consumer history related API methods.
18 '''
19
20
21 import logging
22
23
24 import pymongo
25
26
27 from pulp.server.api.base import BaseApi
28 from pulp.server.db.connection import get_object_db
29 from pulp.server.db.model import ConsumerHistoryEvent
30 from pulp.server.pexceptions import PulpException
31
32
33
34
35 LOG = logging.getLogger(__name__)
36
37
38 TYPE_CONSUMER_CREATED = 'consumer_created'
39 TYPE_CONSUMER_DELETED = 'consumer_deleted'
40 TYPE_REPO_BOUND = 'repo_bound'
41 TYPE_REPO_UNBOUND = 'repo_unbound'
42 TYPE_PACKAGE_INSTALLED = 'package_installed'
43 TYPE_PACKAGE_UNINSTALLED = 'package_uninstalled'
44 TYPE_PROFILE_CHANGED = 'profile_changed'
45
46 TYPES = (TYPE_CONSUMER_CREATED, TYPE_CONSUMER_DELETED, TYPE_REPO_BOUND,
47 TYPE_REPO_UNBOUND, TYPE_PACKAGE_INSTALLED, TYPE_PACKAGE_UNINSTALLED,
48 TYPE_PROFILE_CHANGED)
49
50
51 ORIGINATOR_CONSUMER = 'consumer'
52
53
54 SORT_ASCENDING = 'ascending'
55 SORT_DESCENDING = 'descending'
56 SORT_DIRECTION = {
57 SORT_ASCENDING : pymongo.ASCENDING,
58 SORT_DESCENDING : pymongo.DESCENDING,
59 }
60
61
62 -class ConsumerHistoryApi(BaseApi):
63
64
65
68
69 - def _getcollection(self):
70 return get_object_db('consumer_history',
71 self._unique_indexes,
72 self._indexes)
73
75 '''
76 The circular dependency of requiring the consumer API causes issues, so
77 when looking up a consumer as a validation check we go directly to the consumer
78 collection. This method returns a hook to that collection.
79
80 @return: pymongo database connection to the consumer connection
81 @rtype: ?
82 '''
83 return get_object_db('consumers',
84 ['id'],
85 [])
86
87
88
89 - def query(self, consumer_id=None, event_type=None, limit=None, sort='descending',
90 start_date=None, end_date=None):
91 '''
92 Queries the consumer history storage.
93
94 @param consumer_id: if specified, events will only be returned for the the
95 consumer referenced; an error is raised if there is no
96 consumer for the given ID
97 @type consumer_id: string or number
98
99 @param event_type: if specified, only events of the given type are returned;
100 an error is raised if the event type mentioned is not listed
101 in the results of the L{event_types} call
102 @type event_type: string (enumeration found in TYPES)
103
104 @param limit: if specified, the query will only return up to this amount of
105 entries; default is to not limit the entries returned
106 @type limit: number greater than zero
107
108 @param sort: indicates the sort direction of the results; results are sorted
109 by timestamp
110 @type sort: string; valid values are 'ascending' and 'descending'
111
112 @param start_date: if specified, no events prior to this date will be returned
113 @type start_date: L{datetime.datetime}
114
115 @param end_date: if specified, no events after this date will be returned
116 @type end_date: L{datetime.datetime}
117
118 @return: list of consumer history entries that match the given parameters;
119 empty list (not None) if no matching entries are found
120 @rtype: list of L{pulp.server.db.model.ConsumerHistoryEvent} instances
121
122 @raise PulpException: if any of the input values are invalid
123 '''
124
125
126 if consumer_id:
127 consumer_db = self._get_consumer_collection()
128 if len(list(consumer_db.find({'id' : consumer_id}))) == 0:
129 raise PulpException('Invalid consumer ID [%s]' % consumer_id)
130
131
132 if event_type and event_type not in TYPES:
133 raise PulpException('Invalid event type [%s]' % event_type)
134
135
136 if limit is not None and limit < 1:
137 raise PulpException('Invalid limit [%s], limit must be greater than zero' % limit)
138
139
140 if not sort in SORT_DIRECTION:
141 valid_sorts = ', '.join(SORT_DIRECTION)
142 raise PulpException('Invalid sort direction [%s], valid values [%s]' % (sort, valid_sorts))
143
144
145 search_params = {}
146 if consumer_id:
147 search_params['consumer_id'] = consumer_id
148 if event_type:
149 search_params['type_name'] = event_type
150
151
152 date_range = {}
153 if start_date:
154 date_range['$gt'] = start_date
155 if end_date:
156 date_range['$lt'] = end_date
157
158 if len(date_range) > 0:
159 search_params['timestamp'] = date_range
160
161
162 if len(search_params) == 0:
163 cursor = self.objectdb.find()
164 else:
165 cursor = self.objectdb.find(search_params)
166
167
168 cursor.sort('timestamp', direction=SORT_DIRECTION[sort])
169
170
171 if limit:
172 cursor.limit(limit)
173
174
175 return list(cursor)
176
177 - def event_types(self):
179
180
181
182 - def consumer_created(self, consumer_id, originator=ORIGINATOR_CONSUMER):
183 '''
184 Creates a new event to represent a consumer being created.
185
186 @param consumer_id: identifies the newly created consumer
187 @type consumer_id: string or number
188
189 @param originator: if specified, should be the username of the admin who created
190 the consumer through the admin API; defaults to indicate the
191 create was triggered by the consumer itself
192 @type originator: string
193 '''
194 event = ConsumerHistoryEvent(consumer_id, originator, TYPE_CONSUMER_CREATED, None)
195 self.insert(event)
196
197 - def consumer_deleted(self, consumer_id, originator=ORIGINATOR_CONSUMER):
198 '''
199 Creates a new event to represent a consumer being deleted.
200
201 @param consumer_id: identifies the deleted consumer
202 @type consumer_id: string or number
203
204 @param originator: if specified, should be the username of the admin who deleted
205 the consumer through the admin API; defaults to indicate the
206 create was triggered by the consumer itself
207 @type originator: string
208 '''
209 event = ConsumerHistoryEvent(consumer_id, originator, TYPE_CONSUMER_DELETED, None)
210 self.insert(event)
211
212 - def repo_bound(self, consumer_id, repo_id, originator=ORIGINATOR_CONSUMER):
213 '''
214 Creates a new event to represent a consumer binding to a repo.
215
216 @param consumer_id: identifies the consumer being modified
217 @type consumer_id: string or number
218
219 @param repo_id: identifies the repo being bound to the consumer
220 @type repo_id: string or number
221
222 @param originator: if specified, should be the username of the admin who bound
223 the repo through the admin API; defaults to indicate the
224 create was triggered by the consumer itself
225 @type originator: string
226 '''
227 details = {'repo_id' : repo_id}
228 event = ConsumerHistoryEvent(consumer_id, originator, TYPE_REPO_BOUND, details)
229 self.insert(event)
230
231 - def repo_unbound(self, consumer_id, repo_id, originator=ORIGINATOR_CONSUMER):
232 '''
233 Creates a new event to represent removing a binding from a repo.
234
235 @param consumer_id: identifies the consumer being modified
236 @type consumer_id: string or number
237
238 @param repo_id: identifies the repo being unbound from the consumer
239 @type repo_id: string or number
240
241 @param originator: if specified, should be the username of the admin who unbound
242 the repo through the admin API; defaults to indicate the
243 create was triggered by the consumer itself
244 @type originator: string
245 '''
246 details = {'repo_id' : repo_id}
247 event = ConsumerHistoryEvent(consumer_id, originator, TYPE_REPO_UNBOUND, details)
248 self.insert(event)
249
250 - def packages_installed(self, consumer_id, package_nveras, originator=ORIGINATOR_CONSUMER):
251 '''
252 Creates a new event to represent packages that were installed on a consumer.
253
254 @param consumer_id: identifies the consumer being modified
255 @type consumer_id: string or number
256
257 @param package_nveras: identifies the packages that were installed on the consumer
258 @type package_nveras: list or string; a single string will automatically be wrapped
259 in a list
260
261 @param originator: if specified, should be the username of the admin who installed
262 packages through the admin API; defaults to indicate the
263 create was triggered by the consumer itself
264 @type originator: string
265 '''
266 if type(package_nveras) != list:
267 package_nveras = [package_nveras]
268
269 details = {'package_nveras' : package_nveras}
270 event = ConsumerHistoryEvent(consumer_id, originator, TYPE_PACKAGE_INSTALLED, details)
271 self.insert(event)
272
273 - def packages_removed(self, consumer_id, package_nveras, originator=ORIGINATOR_CONSUMER):
274 '''
275 Creates a new event to represent packages that were removed from a consumer.
276
277 @param consumer_id: identifies the consumer being modified
278 @type consumer_id: string or number
279
280 @param package_nveras: identifies the packages that were removed from the consumer
281 @type package_nveras: list or string; a single string will automatically be wrapped
282 in a list
283
284 @param originator: if specified, should be the username of the admin who removed
285 packages through the admin API; defaults to indicate the
286 create was triggered by the consumer itself
287 @type originator: string
288 '''
289 if type(package_nveras) != list:
290 package_nveras = [package_nveras]
291
292 details = {'package_nveras' : package_nveras}
293 event = ConsumerHistoryEvent(consumer_id, originator, TYPE_PACKAGE_UNINSTALLED, details)
294 self.insert(event)
295