Merge lp:~javier.collado/utah/utah_client_common_docs into lp:utah

Proposed by Javier Collado
Status: Merged
Approved by: Javier Collado
Approved revision: 823
Merged at revision: 824
Proposed branch: lp:~javier.collado/utah/utah_client_common_docs
Merge into: lp:utah
Diff against target: 511 lines (+245/-63)
2 files modified
docs/source/reference.rst (+3/-0)
utah/client/common.py (+242/-63)
To merge this branch: bzr merge lp:~javier.collado/utah/utah_client_common_docs
Reviewer Review Type Date Requested Status
Joe Talbott (community) Approve
UTAH Dev Pending
Review via email: mp+150740@code.launchpad.net

Description of the change

This branch add some text to the documentation strings in utah.client.common
module.

To post a comment you must log in.
Revision history for this message
Joe Talbott (joetalbott) wrote :

Looks good. Thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'docs/source/reference.rst'
--- docs/source/reference.rst 2012-12-12 20:58:59 +0000
+++ docs/source/reference.rst 2013-02-27 09:07:24 +0000
@@ -59,6 +59,9 @@
5959
60.. automodule:: utah.client60.. automodule:: utah.client
6161
62``utah.client.common``
63----------------------
64
62.. automodule:: utah.client.common65.. automodule:: utah.client.common
63 :members:66 :members:
6467
6568
=== modified file 'utah/client/common.py'
--- utah/client/common.py 2013-02-15 08:55:48 +0000
+++ utah/client/common.py 2013-02-27 09:07:24 +0000
@@ -13,9 +13,7 @@
13# You should have received a copy of the GNU General Public License along13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.14# with this program. If not, see <http://www.gnu.org/licenses/>.
1515
16"""16"""UTAH client common classes and functions."""
17Common methods.
18"""
1917
20import datetime18import datetime
21import re19import re
@@ -75,16 +73,39 @@
7573
7674
77def do_nothing(_obj=None):75def do_nothing(_obj=None):
78 """76 """Placeholder for save_state_callbacks.
79 Do nothing method used a placeholder for save_state_callbacks.77
80 """78 .. seealso:: :class:`.TestSuite`, :class:`.TestCase`
81 pass79
80 """
8281
8382
84# Inspired by:83# Inspired by:
85# http://stackoverflow.com/a/332655984# http://stackoverflow.com/a/3326559
86def run_cmd(command, cwd=None, timeout=0, cmd_type=CMD_TC_TEST, run_as=None,85def run_cmd(command, cwd=None, timeout=0, cmd_type=CMD_TC_TEST, run_as=None,
87 battery_measurements=False):86 battery_measurements=False):
87 """Run command and return result using the client's format.
88
89 :param command: Command as it would be written in a console
90 :type command: str
91 :param cwd: Current working directory path
92 :type cwd: str
93 :param timeout:
94 Maximum amount of time in seconds to wait for the command to complete
95 :type timeout: int
96 :param cmd_type: Command type as displayed in the result object
97 :type cmd_type: str
98 :param run_as: Username to use to run the command
99 :type run_as: int
100 :param battery_measurements:
101 Flag to configure when to get battery related information
102 :type battery_measurements: bool
103 :returns: Command execution result
104 :rtype: dict
105
106 .. seealso:: :func:`make_result`
107
108 """
88109
89 if run_as is not None:110 if run_as is not None:
90 # add -n so sudo will not prompt for a password on the tty111 # add -n so sudo will not prompt for a password on the tty
@@ -172,6 +193,13 @@
172 Make sure that byte strings are used only for ascii data and unicode193 Make sure that byte strings are used only for ascii data and unicode
173 strings for strings using any other encoding.194 strings for strings using any other encoding.
174195
196 :param value: Data string that should be normalized
197 :type value: str
198 :param encoding: Encoding used to decode the given string
199 :type encoding: str
200 :returns: Data string reencoded using in ascii if possible
201 :rtype: str
202
175 """203 """
176 unicode_value = value.decode(encoding)204 unicode_value = value.decode(encoding)
177 try:205 try:
@@ -185,10 +213,37 @@
185# TODO: it might make sense to have a result object that keeps track of213# TODO: it might make sense to have a result object that keeps track of
186# test pass, fail, error and serializes it's data.214# test pass, fail, error and serializes it's data.
187def make_result(command, retcode, stdout='', stderr='', start_time='',215def make_result(command, retcode, stdout='', stderr='', start_time='',
188 time_delta='', cmd_type=CMD_TC_TEST, user="unknown",216 time_delta='', cmd_type=CMD_TC_TEST, user='unknown',
189 start_battery=None, end_battery=None):217 start_battery=None, end_battery=None):
190 """218 """Make a result data structure.
191 Make a result dictionary.219
220 .. note::
221 Battery information will only be included if some value is passed as
222 argument.
223
224 :param command: Command that was executed
225 :type command: str
226 :param retcode: Return code
227 :type retcode: int
228 :param stdout: Standard output
229 :type stdout: str
230 :param stderr: Standard error
231 :type stderr: str
232 :param start_time: Time in which command execution started
233 :type start_time: str
234 :param time_delta: Amount of time that the command took to complete
235 :type time_delta: str
236 :param cmd_type: Command type to be displayed in the report
237 :type cmd_type: str
238 :param user: User name the executed the command
239 :type user: str
240 :param start_battery: Battery information before running the command
241 :type start_battery: dict
242 :param end_battery: Battery information after running the command
243 :type end_battery: dict
244 :returns: Result data
245 :rtype: dict
246
192 """247 """
193 res = {248 res = {
194 'command': command,249 'command': command,
@@ -212,6 +267,14 @@
212267
213268
214def get_process_children(pid):269def get_process_children(pid):
270 """Get the children processes of a given one.
271
272 :param pid: Process ID of the parent process
273 :type pid: int
274 :returns: Process ID for the childern processes
275 :rtype: list(int)
276
277 """
215 p = subprocess.Popen('ps --no-headers -o pid --ppid %d' % pid, shell=True,278 p = subprocess.Popen('ps --no-headers -o pid --ppid %d' % pid, shell=True,
216 stdout=subprocess.PIPE, stderr=subprocess.PIPE)279 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
217 stdout, _stderr = p.communicate()280 stdout, _stderr = p.communicate()
@@ -220,9 +283,18 @@
220283
221284
222def parse_yaml_file(filename):285def parse_yaml_file(filename):
223 """286 """Parse yaml file.
224 Parse yaml file and raise exception with error location287
225 in case of error288 :param filename: Path to the file that should be read
289 :type filename: str
290 :returns: Parsed data
291 :rtype: object
292 :raises YAMLParsingError:
293 If there's a problem while parsing the file with the information about
294 where in the file the problem was detected.
295
296 .. seealso:: :func:`parse_control_file`
297
226 """298 """
227 try:299 try:
228 with open(filename, 'r') as fp:300 with open(filename, 'r') as fp:
@@ -247,7 +319,16 @@
247# Validator that sets values to defaults as explained in:319# Validator that sets values to defaults as explained in:
248# https://github.com/Julian/jsonschema/issues/4320# https://github.com/Julian/jsonschema/issues/4
249class DefaultValidator(jsonschema.Validator):321class DefaultValidator(jsonschema.Validator):
322
323 """jsonschema validator that sets default values.
324
325 During the validation, if some field is missing in the data, it will be set
326 to the default value specified in the schema if defined.
327
328 """
329
250 def validate_properties(self, properties, instance, schema):330 def validate_properties(self, properties, instance, schema):
331 """Set missing properties to default value."""
251 (super(DefaultValidator, self)332 (super(DefaultValidator, self)
252 .validate_properties(properties, instance, schema))333 .validate_properties(properties, instance, schema))
253 instance.update((k, v['default'])334 instance.update((k, v['default'])
@@ -256,8 +337,19 @@
256337
257338
258def parse_control_file(filename, schema):339def parse_control_file(filename, schema):
259 """340 """Parse a control file and check against a jsonschema.
260 Parse a control file and check against the schema341
342 :param filename: Path to the yaml file to be parsed
343 :type filename: str
344 :param schema: jsonschema to validate data against
345 :type schema: dict
346 :returns: Parsed data
347 :rtype: object
348 :raises jsonschema.ValidationError:
349 If file contents doesn't follow the schema definitions
350
351 .. seealso:: :func:`parse_yaml_file`, :class:`DefaultValidator`
352
261 """353 """
262 control_data = parse_yaml_file(filename)354 control_data = parse_yaml_file(filename)
263 validator = DefaultValidator()355 validator = DefaultValidator()
@@ -266,8 +358,17 @@
266358
267359
268def debug_print(data, force=False):360def debug_print(data, force=False):
269 """361 """Print debugging information according to ``CONFIG['DEBUG']`` value.
270 Print debugging information if CONFIG['DEBUG'] is defined and True362
363 Data will be printed with the ``DEBUG:`` string prepended to it.
364
365 :param data: Data to be printed
366 :type data: object
367 :param force: Print data regardless of the configuration
368 :type force: bool
369 :returns: Whether something was printed or not
370 :rtype: bool
371
271 """372 """
272 try:373 try:
273 debug = CONFIG['DEBUG']374 debug = CONFIG['DEBUG']
@@ -284,8 +385,11 @@
284385
285386
286def raise_privileges(orig_privs):387def raise_privileges(orig_privs):
287 """388 """Raise privileges to original effective privileges.
288 Raise privileges to original effective privileges.389
390 :param orig_privs: Original privileges
391 :type orig_privs: dict
392
289 """393 """
290 os.seteuid(orig_privs['euid'])394 os.seteuid(orig_privs['euid'])
291 os.setegid(orig_privs['egid'])395 os.setegid(orig_privs['egid'])
@@ -293,12 +397,18 @@
293397
294398
295def drop_privileges(user='nobody', group='nogroup', full=False):399def drop_privileges(user='nobody', group='nogroup', full=False):
296 """400 """Change user and/or group to decrease privileges.
297 Change user and/or group to decrease privileges.
298401
299 Currently only drops effective privileges.402 Currently only drops effective privileges.
300403
301 Returns a dictionary of the original values.404 :param user: User name to change to.
405 :type user: str
406 :param group: Group name to change to.
407 :type group: str
408
409 :returns: Original prrivileges
410 :rtype: dict
411
302 """412 """
303413
304 orig_privs = {}414 orig_privs = {}
@@ -333,8 +443,13 @@
333443
334444
335def gather_artifacts(extras=None, excludes=None):445def gather_artifacts(extras=None, excludes=None):
336 """446 """Print files contents, so that it's included in the logs.
337 Include a set of useful artifacts (i.e. files) for the logs.447
448 :param extras: Path to files to be included in the artifacts
449 :type extras: list(str)
450 :param excludes: Path to files to be exluded from the artifacts
451 :type excludes: list(str)
452
338 """453 """
339 if extras is None:454 if extras is None:
340 extras = []455 extras = []
@@ -366,12 +481,14 @@
366481
367482
368def get_media_info():483def get_media_info():
369 """484 """Get the contents of the media-info file if available.
370 Get the contents of the media-info file if available.485
371486 :returns:
372 NOTE: This is only a best-effort approach.487 The contents of the media-info file or ``'unknown'`` if not available.
373488 :rtype: str
374 Returns the contents of the media-info file or None.489
490 .. note:: This is only a best-effort approach.
491
375 """492 """
376493
377 filename = '/var/log/installer/media-info'494 filename = '/var/log/installer/media-info'
@@ -386,12 +503,13 @@
386503
387504
388def get_product_uuid():505def get_product_uuid():
389 """506 """Get the product_uuid of the machine under test.
390 Get the product_uuid of the machine under test.507
391508 :returns:
392 NOTE: This is only a best-effort approach.509 The contents of the product_uuid file or ``None`` if not available.
393510
394 Returns the contents of the product_uuid file or None.511 .. note:: This is only a best-effort approach.
512
395 """513 """
396514
397 filename = '/sys/class/dmi/id/product_uuid'515 filename = '/sys/class/dmi/id/product_uuid'
@@ -406,8 +524,13 @@
406524
407525
408def get_host_info():526def get_host_info():
409 """527 """Get host info, useful for debugging.
410 Get host info, useful for debugging.528
529 :returns: Host uname, media-info and product_uuid together
530 :rtype: dict
531
532 .. seealso:: :func:`get_media_info`, :func:`get_product_uuid`
533
411 """534 """
412535
413 retval = {}536 retval = {}
@@ -421,10 +544,11 @@
421544
422545
423def get_arch():546def get_arch():
424 """547 """Get the host's architecture.
425 The host's architecture.548
426549 :returns: The human readable architecture or ``'unknown'``
427 Returns the human readable architecture or 'unknown'.550 :rtype: str
551
428 """552 """
429 arches = {553 arches = {
430 'x86_64': 'amd64',554 'x86_64': 'amd64',
@@ -436,15 +560,20 @@
436560
437561
438def get_release():562def get_release():
439 """563 """Get the host's release name.
440 The host's release name (i.e. precise, quantal, etc.)564
441 """565 :returns: Release name (i.e. quantal, raring, etc.)
442 return platform.dist()[2]566 :rtype: str
567
568 """
569 return platform.linux_distribution()[2]
443570
444571
445def get_api_config():572def get_api_config():
446 """573 """Parse the client configuration file for API configuration data.
447 Parse the client configuration file for API configuration data.574
575 :returns: The value for the ``API`` field in the client configuration file.
576
448 """577 """
449578
450 data = {}579 data = {}
@@ -457,6 +586,14 @@
457586
458587
459def get_build_number():588def get_build_number():
589 """Get build number.
590
591 :returns: Build number as according to media-info or ``'?'`` if not found
592 :rtype: str
593
594 .. seealso:: :func:`get_host_info`
595
596 """
460 host_info = get_host_info()597 host_info = get_host_info()
461 pattern = re.compile('.*\(([0-9.]+)\)$')598 pattern = re.compile('.*\(([0-9.]+)\)$')
462 match = pattern.match(host_info['media-info'])599 match = pattern.match(host_info['media-info'])
@@ -469,8 +606,19 @@
469606
470607
471class VCSHandler(object):608class VCSHandler(object):
472 """609
473 Base class for Version Ccontrol System support.610 """Base class for Version Control System support.
611
612 :param repo: Repository location
613 :type repo: str
614 :param destination:
615 Local directory where the repository should be made available
616 :type destination: str
617 :param battery_measurements:
618 Whether battery information should be gathered when running any of the
619 VCS commands
620 :type battery_measurements: bool
621
474 """622 """
475623
476 def __init__(self, repo, destination='', battery_measurements=False):624 def __init__(self, repo, destination='', battery_measurements=False):
@@ -479,8 +627,18 @@
479 self.battery_measurements = battery_measurements627 self.battery_measurements = battery_measurements
480628
481 def get(self, directory=REPO_DEFAULT_DIR):629 def get(self, directory=REPO_DEFAULT_DIR):
482 """630 """Execute VCS get command.
483 Method to retrieve a copy of the repository631
632 The get command will make a copy of a given repository to the directory
633 specified as destination.
634
635 :param directory: Working directory
636 :type directory: str
637 :returns: Get command execution result
638 :rtype: dict
639
640 .. seealso:: :func:`run_cmd`
641
484 """642 """
485 return run_cmd(self.get_command,643 return run_cmd(self.get_command,
486 cwd=directory,644 cwd=directory,
@@ -488,8 +646,15 @@
488 battery_measurements=self.battery_measurements)646 battery_measurements=self.battery_measurements)
489647
490 def revision(self, directory=REPO_DEFAULT_DIR):648 def revision(self, directory=REPO_DEFAULT_DIR):
491 """649 """Execute revision command.
492 Return the revision identifier.650
651 :param directory: Working directory
652 :type directory: str
653 :returns: Revision command execution result.
654 :rtype: dict
655
656 .. seealso:: :func:`run_cmd`, :meth:`get_revision`
657
493 """658 """
494 return run_cmd(self.rev_command,659 return run_cmd(self.rev_command,
495 cwd=directory,660 cwd=directory,
@@ -497,8 +662,18 @@
497 battery_measurements=self.battery_measurements)662 battery_measurements=self.battery_measurements)
498663
499 def get_revision(self, directory=REPO_DEFAULT_DIR):664 def get_revision(self, directory=REPO_DEFAULT_DIR):
500 """665 """Print revision information.
501 get the revision information666
667 This is a wrapper around :meth:`revision` to make sure that the command
668 returned a success code.
669
670 :param directory: Working directory
671 :type directory: str
672 :returns: Revision command returncode
673 :rtype: int
674
675 .. seealso:: :meth:`revision`
676
502 """677 """
503 retval = None678 retval = None
504 result = self.revision(directory=directory)679 result = self.revision(directory=directory)
@@ -512,9 +687,8 @@
512687
513688
514class BzrHandler(VCSHandler):689class BzrHandler(VCSHandler):
515 """690
516 bazaar handler.691 """Bazaar VCS handler."""
517 """
518692
519 def __init__(self, repo, branch=True, options="", destination="",693 def __init__(self, repo, branch=True, options="", destination="",
520 **kwargs):694 **kwargs):
@@ -540,9 +714,8 @@
540714
541715
542class GitHandler(VCSHandler):716class GitHandler(VCSHandler):
543 """717
544 git handler.718 """Git VCS handler."""
545 """
546719
547 def __init__(self, repo, options="", destination="", **kwargs):720 def __init__(self, repo, options="", destination="", **kwargs):
548 super(GitHandler, self).__init__(repo, destination, **kwargs)721 super(GitHandler, self).__init__(repo, destination, **kwargs)
@@ -558,7 +731,13 @@
558731
559732
560class DevHandler(VCSHandler):733class DevHandler(VCSHandler):
561 """ Copy from a local directory for development. """734
735 """Development VCS handler.
736
737 This isn't a handler for any VCS, but a helper to ease development and let
738 runlists point to a path that can be copied locally.
739
740 """
562741
563 def __init__(self, repo, destination=".", **kwargs):742 def __init__(self, repo, destination=".", **kwargs):
564 super(DevHandler, self).__init__(repo, destination, **kwargs)743 super(DevHandler, self).__init__(repo, destination, **kwargs)

Subscribers

People subscribed via source and target branches