Python freezer client
Split apiclient from freezer-agent repo Use cliff as a cli for freezer Implements bp: freezerclient
This commit is contained in:
		
							
								
								
									
										29
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
__pycache__
 | 
			
		||||
dist
 | 
			
		||||
build
 | 
			
		||||
.venv
 | 
			
		||||
tests/scenario/.vagrant
 | 
			
		||||
.idea
 | 
			
		||||
.autogenerated
 | 
			
		||||
.coverage
 | 
			
		||||
cover/
 | 
			
		||||
coverage.xml
 | 
			
		||||
*.sw?
 | 
			
		||||
.tox
 | 
			
		||||
*.egg
 | 
			
		||||
*.egg-info
 | 
			
		||||
*.py[co]
 | 
			
		||||
.DS_Store
 | 
			
		||||
*.log
 | 
			
		||||
.testrepository
 | 
			
		||||
subunit.log
 | 
			
		||||
.eggs
 | 
			
		||||
AUTHORS
 | 
			
		||||
ChangeLog
 | 
			
		||||
 | 
			
		||||
# Django files that get created during the test runs
 | 
			
		||||
.secret_key_store
 | 
			
		||||
*.lock
 | 
			
		||||
 | 
			
		||||
# Coverage data
 | 
			
		||||
.coverage.*
 | 
			
		||||
							
								
								
									
										333
									
								
								.pylintrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										333
									
								
								.pylintrc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,333 @@
 | 
			
		||||
[MASTER]
 | 
			
		||||
 | 
			
		||||
# Specify a configuration file.
 | 
			
		||||
#rcfile=
 | 
			
		||||
 | 
			
		||||
# Python code to execute, usually for sys.path manipulation such as
 | 
			
		||||
# pygtk.require().
 | 
			
		||||
#init-hook=
 | 
			
		||||
 | 
			
		||||
# Profiled execution.
 | 
			
		||||
profile=no
 | 
			
		||||
 | 
			
		||||
# Add files or directories to the blacklist. They should be base names, not
 | 
			
		||||
# paths.
 | 
			
		||||
ignore=CVS
 | 
			
		||||
 | 
			
		||||
# Pickle collected data for later comparisons.
 | 
			
		||||
persistent=no
 | 
			
		||||
 | 
			
		||||
# List of plugins (as comma separated values of python modules names) to load,
 | 
			
		||||
# usually to register additional checkers.
 | 
			
		||||
load-plugins=
 | 
			
		||||
 | 
			
		||||
# DEPRECATED
 | 
			
		||||
include-ids=no
 | 
			
		||||
 | 
			
		||||
# DEPRECATED
 | 
			
		||||
symbols=no
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[MESSAGES CONTROL]
 | 
			
		||||
 | 
			
		||||
# Enable the message, report, category or checker with the given id(s). You can
 | 
			
		||||
# either give multiple identifier separated by comma (,) or put this option
 | 
			
		||||
# multiple time. See also the "--disable" option for examples.
 | 
			
		||||
#enable=
 | 
			
		||||
 | 
			
		||||
# Disable the message, report, category or checker with the given id(s). You
 | 
			
		||||
# can either give multiple identifiers separated by comma (,) or put this
 | 
			
		||||
# option multiple times (only on the command line, not in the configuration
 | 
			
		||||
# file where it should appear only once).You can also use "--disable=all" to
 | 
			
		||||
# disable everything first and then reenable specific checks. For example, if
 | 
			
		||||
# you want to run only the similarities checker, you can use "--disable=all
 | 
			
		||||
# --enable=similarities". If you want to run only the classes checker, but have
 | 
			
		||||
# no Warning level messages displayed, use"--disable=all --enable=classes
 | 
			
		||||
# --disable=W"
 | 
			
		||||
disable=W,C,R
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[REPORTS]
 | 
			
		||||
 | 
			
		||||
# Set the output format. Available formats are text, parseable, colorized, msvs
 | 
			
		||||
# (visual studio) and html. You can also give a reporter class, eg
 | 
			
		||||
# mypackage.mymodule.MyReporterClass.
 | 
			
		||||
output-format=text
 | 
			
		||||
 | 
			
		||||
# Put messages in a separate file for each module / package specified on the
 | 
			
		||||
# command line instead of printing them on stdout. Reports (if any) will be
 | 
			
		||||
# written in a file name "pylint_global.[txt|html]".
 | 
			
		||||
files-output=no
 | 
			
		||||
 | 
			
		||||
# Tells whether to display a full report or only the messages
 | 
			
		||||
reports=no
 | 
			
		||||
 | 
			
		||||
# Python expression which should return a note less than 10 (10 is the highest
 | 
			
		||||
# note). You have access to the variables errors warning, statement which
 | 
			
		||||
# respectively contain the number of errors / warnings messages and the total
 | 
			
		||||
# number of statements analyzed. This is used by the global evaluation report
 | 
			
		||||
# (RP0004).
 | 
			
		||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
 | 
			
		||||
 | 
			
		||||
# Add a comment according to your evaluation note. This is used by the global
 | 
			
		||||
# evaluation report (RP0004).
 | 
			
		||||
comment=no
 | 
			
		||||
 | 
			
		||||
# Template used to display messages. This is a python new-style format string
 | 
			
		||||
# used to format the message information. See doc for all details
 | 
			
		||||
#msg-template=
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[SIMILARITIES]
 | 
			
		||||
 | 
			
		||||
# Minimum lines number of a similarity.
 | 
			
		||||
min-similarity-lines=4
 | 
			
		||||
 | 
			
		||||
# Ignore comments when computing similarities.
 | 
			
		||||
ignore-comments=yes
 | 
			
		||||
 | 
			
		||||
# Ignore docstrings when computing similarities.
 | 
			
		||||
ignore-docstrings=yes
 | 
			
		||||
 | 
			
		||||
# Ignore imports when computing similarities.
 | 
			
		||||
ignore-imports=no
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[TYPECHECK]
 | 
			
		||||
 | 
			
		||||
# Tells whether missing members accessed in mixin class should be ignored. A
 | 
			
		||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
 | 
			
		||||
ignore-mixin-members=yes
 | 
			
		||||
 | 
			
		||||
# List of module names for which member attributes should not be checked
 | 
			
		||||
# (useful for modules/projects where namespaces are manipulated during runtime
 | 
			
		||||
# and thus extisting member attributes cannot be deduced by static analysis
 | 
			
		||||
ignored-modules=distutils
 | 
			
		||||
 | 
			
		||||
# List of classes names for which member attributes should not be checked
 | 
			
		||||
# (useful for classes with attributes dynamically set).
 | 
			
		||||
ignored-classes=SQLObject
 | 
			
		||||
 | 
			
		||||
# When zope mode is activated, add a predefined set of Zope acquired attributes
 | 
			
		||||
# to generated-members.
 | 
			
		||||
zope=no
 | 
			
		||||
 | 
			
		||||
# List of members which are set dynamically and missed by pylint inference
 | 
			
		||||
# system, and so shouldn't trigger E0201 when accessed. Python regular
 | 
			
		||||
# expressions are accepted.
 | 
			
		||||
generated-members=REQUEST,acl_users,aq_parent,BackupJob.time_stamp,BackupJob.start_time
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[MISCELLANEOUS]
 | 
			
		||||
 | 
			
		||||
# List of note tags to take in consideration, separated by a comma.
 | 
			
		||||
notes=FIXME,XXX,TODO
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[BASIC]
 | 
			
		||||
 | 
			
		||||
# Required attributes for module, separated by a comma
 | 
			
		||||
required-attributes=
 | 
			
		||||
 | 
			
		||||
# List of builtins function names that should not be used, separated by a comma
 | 
			
		||||
bad-functions=map,filter,apply,input,file
 | 
			
		||||
 | 
			
		||||
# Good variable names which should always be accepted, separated by a comma
 | 
			
		||||
good-names=i,j,k,ex,Run,_
 | 
			
		||||
 | 
			
		||||
# Bad variable names which should always be refused, separated by a comma
 | 
			
		||||
bad-names=foo,bar,baz,toto,tutu,tata
 | 
			
		||||
 | 
			
		||||
# Colon-delimited sets of names that determine each other's naming style when
 | 
			
		||||
# the name regexes allow several styles.
 | 
			
		||||
name-group=
 | 
			
		||||
 | 
			
		||||
# Include a hint for the correct naming format with invalid-name
 | 
			
		||||
include-naming-hint=no
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct function names
 | 
			
		||||
function-rgx=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Naming hint for function names
 | 
			
		||||
function-name-hint=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct variable names
 | 
			
		||||
variable-rgx=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Naming hint for variable names
 | 
			
		||||
variable-name-hint=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct constant names
 | 
			
		||||
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
 | 
			
		||||
 | 
			
		||||
# Naming hint for constant names
 | 
			
		||||
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct attribute names
 | 
			
		||||
attr-rgx=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Naming hint for attribute names
 | 
			
		||||
attr-name-hint=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct argument names
 | 
			
		||||
argument-rgx=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Naming hint for argument names
 | 
			
		||||
argument-name-hint=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct class attribute names
 | 
			
		||||
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
 | 
			
		||||
 | 
			
		||||
# Naming hint for class attribute names
 | 
			
		||||
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct inline iteration names
 | 
			
		||||
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
 | 
			
		||||
 | 
			
		||||
# Naming hint for inline iteration names
 | 
			
		||||
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct class names
 | 
			
		||||
class-rgx=[A-Z_][a-zA-Z0-9]+$
 | 
			
		||||
 | 
			
		||||
# Naming hint for class names
 | 
			
		||||
class-name-hint=[A-Z_][a-zA-Z0-9]+$
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct module names
 | 
			
		||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
 | 
			
		||||
 | 
			
		||||
# Naming hint for module names
 | 
			
		||||
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
 | 
			
		||||
 | 
			
		||||
# Regular expression matching correct method names
 | 
			
		||||
method-rgx=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Naming hint for method names
 | 
			
		||||
method-name-hint=[a-z_][a-z0-9_]{2,30}$
 | 
			
		||||
 | 
			
		||||
# Regular expression which should only match function or class names that do
 | 
			
		||||
# not require a docstring.
 | 
			
		||||
no-docstring-rgx=__.*__
 | 
			
		||||
 | 
			
		||||
# Minimum line length for functions/classes that require docstrings, shorter
 | 
			
		||||
# ones are exempt.
 | 
			
		||||
docstring-min-length=-1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[VARIABLES]
 | 
			
		||||
 | 
			
		||||
# Tells whether we should check for unused import in __init__ files.
 | 
			
		||||
init-import=no
 | 
			
		||||
 | 
			
		||||
# A regular expression matching the name of dummy variables (i.e. expectedly
 | 
			
		||||
# not used).
 | 
			
		||||
dummy-variables-rgx=_$|dummy
 | 
			
		||||
 | 
			
		||||
# List of additional names supposed to be defined in builtins. Remember that
 | 
			
		||||
# you should avoid to define new builtins when possible.
 | 
			
		||||
additional-builtins=
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[LOGGING]
 | 
			
		||||
 | 
			
		||||
# Logging modules to check that the string format arguments are in logging
 | 
			
		||||
# function parameter format
 | 
			
		||||
logging-modules=logging
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[FORMAT]
 | 
			
		||||
 | 
			
		||||
# Maximum number of characters on a single line.
 | 
			
		||||
max-line-length=80
 | 
			
		||||
 | 
			
		||||
# Regexp for a line that is allowed to be longer than the limit.
 | 
			
		||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
 | 
			
		||||
 | 
			
		||||
# Allow the body of an if to be on the same line as the test if there is no
 | 
			
		||||
# else.
 | 
			
		||||
single-line-if-stmt=no
 | 
			
		||||
 | 
			
		||||
# List of optional constructs for which whitespace checking is disabled
 | 
			
		||||
no-space-check=trailing-comma,dict-separator
 | 
			
		||||
 | 
			
		||||
# Maximum number of lines in a module
 | 
			
		||||
max-module-lines=1000
 | 
			
		||||
 | 
			
		||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
 | 
			
		||||
# tab).
 | 
			
		||||
indent-string='    '
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[DESIGN]
 | 
			
		||||
 | 
			
		||||
# Maximum number of arguments for function / method
 | 
			
		||||
max-args=5
 | 
			
		||||
 | 
			
		||||
# Argument names that match this expression will be ignored. Default to name
 | 
			
		||||
# with leading underscore
 | 
			
		||||
ignored-argument-names=_.*
 | 
			
		||||
 | 
			
		||||
# Maximum number of locals for function / method body
 | 
			
		||||
max-locals=15
 | 
			
		||||
 | 
			
		||||
# Maximum number of return / yield for function / method body
 | 
			
		||||
max-returns=6
 | 
			
		||||
 | 
			
		||||
# Maximum number of branch for function / method body
 | 
			
		||||
max-branches=12
 | 
			
		||||
 | 
			
		||||
# Maximum number of statements in function / method body
 | 
			
		||||
max-statements=50
 | 
			
		||||
 | 
			
		||||
# Maximum number of parents for a class (see R0901).
 | 
			
		||||
max-parents=7
 | 
			
		||||
 | 
			
		||||
# Maximum number of attributes for a class (see R0902).
 | 
			
		||||
max-attributes=7
 | 
			
		||||
 | 
			
		||||
# Minimum number of public methods for a class (see R0903).
 | 
			
		||||
min-public-methods=2
 | 
			
		||||
 | 
			
		||||
# Maximum number of public methods for a class (see R0904).
 | 
			
		||||
max-public-methods=20
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[CLASSES]
 | 
			
		||||
 | 
			
		||||
# List of interface methods to ignore, separated by a comma. This is used for
 | 
			
		||||
# instance to not check methods defines in Zope's Interface base class.
 | 
			
		||||
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
 | 
			
		||||
 | 
			
		||||
# List of method names used to declare (i.e. assign) instance attributes.
 | 
			
		||||
defining-attr-methods=__init__,__new__,setUp
 | 
			
		||||
 | 
			
		||||
# List of valid names for the first argument in a class method.
 | 
			
		||||
valid-classmethod-first-arg=cls
 | 
			
		||||
 | 
			
		||||
# List of valid names for the first argument in a metaclass class method.
 | 
			
		||||
valid-metaclass-classmethod-first-arg=mcs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[IMPORTS]
 | 
			
		||||
 | 
			
		||||
# Deprecated modules which should not be used, separated by a comma
 | 
			
		||||
deprecated-modules=regsub,TERMIOS,Bastion,rexec
 | 
			
		||||
 | 
			
		||||
# Create a graph of every (i.e. internal and external) dependencies in the
 | 
			
		||||
# given file (report RP0402 must not be disabled)
 | 
			
		||||
import-graph=
 | 
			
		||||
 | 
			
		||||
# Create a graph of external dependencies in the given file (report RP0402 must
 | 
			
		||||
# not be disabled)
 | 
			
		||||
ext-import-graph=
 | 
			
		||||
 | 
			
		||||
# Create a graph of internal dependencies in the given file (report RP0402 must
 | 
			
		||||
# not be disabled)
 | 
			
		||||
int-import-graph=
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[EXCEPTIONS]
 | 
			
		||||
 | 
			
		||||
# Exceptions that will emit a warning when being caught. Defaults to
 | 
			
		||||
# "Exception"
 | 
			
		||||
overgeneral-exceptions=Exception
 | 
			
		||||
							
								
								
									
										9
									
								
								.testr.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.testr.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
[DEFAULT]
 | 
			
		||||
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
 | 
			
		||||
             OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
 | 
			
		||||
             OS_LOG_CAPTURE=${OS_LOG_CAPTURE:-1} \
 | 
			
		||||
             ${PYTHON:-python} -m subunit.run discover -s ${OS_TEST_PATH:-./freezerclient/tests/unit} -t . $LISTOPT $IDOPTION
 | 
			
		||||
 | 
			
		||||
test_id_option=--load-list $IDFILE
 | 
			
		||||
test_list_option=--list
 | 
			
		||||
group_regex=([^\.]+\.)+
 | 
			
		||||
							
								
								
									
										17
									
								
								CONTRIBUTING.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								CONTRIBUTING.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
If you would like to contribute to the development of OpenStack, you must
 | 
			
		||||
follow the steps in this page:
 | 
			
		||||
 | 
			
		||||
   http://docs.openstack.org/infra/manual/developers.html
 | 
			
		||||
 | 
			
		||||
If you already have a good understanding of how the system works and your
 | 
			
		||||
OpenStack accounts are set up, you can skip to the development workflow
 | 
			
		||||
section of this documentation to learn how changes to OpenStack should be
 | 
			
		||||
submitted for review via the Gerrit tool:
 | 
			
		||||
 | 
			
		||||
   http://docs.openstack.org/infra/manual/developers.html#development-workflow
 | 
			
		||||
 | 
			
		||||
Pull requests submitted through GitHub will be ignored.
 | 
			
		||||
 | 
			
		||||
Bugs should be filed on Launchpad, not GitHub:
 | 
			
		||||
 | 
			
		||||
   https://bugs.launchpad.net/freezer
 | 
			
		||||
							
								
								
									
										4
									
								
								HACKING.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								HACKING.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
python-freezerclient Style Commandments
 | 
			
		||||
===============================================
 | 
			
		||||
 | 
			
		||||
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
 | 
			
		||||
							
								
								
									
										175
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
 | 
			
		||||
                                 Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
   1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
							
								
								
									
										6
									
								
								MANIFEST.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								MANIFEST.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
include AUTHORS
 | 
			
		||||
include ChangeLog
 | 
			
		||||
exclude .gitignore
 | 
			
		||||
exclude .gitreview
 | 
			
		||||
 | 
			
		||||
global-exclude *.pyc
 | 
			
		||||
							
								
								
									
										25
									
								
								README.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								README.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
===================================================
 | 
			
		||||
Python bindings and CLI for OpenStack's Freezer API
 | 
			
		||||
===================================================
 | 
			
		||||
 | 
			
		||||
This is a client library for Freezer built on the OpenStack Disaster Recovery API. It provides a Python API (the freezerclient module) and a command-line tool (freezer). This library fully supports the v1 Disaster Recovery API.
 | 
			
		||||
 | 
			
		||||
Development takes place via the usual OpenStack processes as outlined in the `developer guide <http://docs.openstack.org/infra/manual/developers.html>`_.  The master repository is in `Git <https://git.openstack.org/cgit/openstack/python-freezerclient>`_.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
* License: Apache License, Version 2.0
 | 
			
		||||
* `PyPi`_ - package installation
 | 
			
		||||
* `Online Documentation`_
 | 
			
		||||
* `Launchpad project`_ - release management
 | 
			
		||||
* `Blueprints`_ - feature specifications
 | 
			
		||||
* `Bugs`_ - issue tracking
 | 
			
		||||
* `Source`_
 | 
			
		||||
* `How to Contribute`_
 | 
			
		||||
 | 
			
		||||
.. _PyPi: https://pypi.python.org/pypi/python-freezerclient
 | 
			
		||||
.. _Online Documentation: https://wiki.openstack.org/wiki/Python-freezerclient
 | 
			
		||||
.. _Launchpad project: https://launchpad.net/python-freezerclient
 | 
			
		||||
.. _Blueprints: https://blueprints.launchpad.net/python-freezerclient
 | 
			
		||||
.. _Bugs: https://bugs.launchpad.net/python-freezerclient
 | 
			
		||||
.. _Source: https://git.openstack.org/cgit/openstack/python-freezerclient
 | 
			
		||||
.. _How to Contribute: http://docs.openstack.org/infra/manual/developers.html
 | 
			
		||||
							
								
								
									
										261
									
								
								client.py
									
									
									
									
									
								
							
							
						
						
									
										261
									
								
								client.py
									
									
									
									
									
								
							@@ -1,261 +0,0 @@
 | 
			
		||||
"""
 | 
			
		||||
Copyright 2015 Hewlett-Packard
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
client interface to the Freezer API
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import socket
 | 
			
		||||
 | 
			
		||||
from keystoneclient.auth.identity import v2
 | 
			
		||||
from keystoneclient.auth.identity import v3
 | 
			
		||||
from keystoneclient import session as ksc_session
 | 
			
		||||
from oslo_config import cfg
 | 
			
		||||
 | 
			
		||||
from freezer.apiclient import actions
 | 
			
		||||
from freezer.apiclient import backups
 | 
			
		||||
from freezer.apiclient import jobs
 | 
			
		||||
from freezer.apiclient import registration
 | 
			
		||||
from freezer.apiclient import sessions
 | 
			
		||||
from freezer.utils import Namespace
 | 
			
		||||
 | 
			
		||||
CONF = cfg.CONF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
FREEZER_SERVICE_TYPE = 'backup'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def env(*vars, **kwargs):
 | 
			
		||||
    for v in vars:
 | 
			
		||||
        value = os.environ.get(v, None)
 | 
			
		||||
        if value:
 | 
			
		||||
            return value
 | 
			
		||||
    return kwargs.get('default', '')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class cached_property(object):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, func):
 | 
			
		||||
        self.__doc__ = getattr(func, '__doc__')
 | 
			
		||||
        self.func = func
 | 
			
		||||
 | 
			
		||||
    def __get__(self, obj, cls):
 | 
			
		||||
        if obj is None:
 | 
			
		||||
            return self
 | 
			
		||||
        value = obj.__dict__[self.func.__name__] = self.func(obj)
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def build_os_options():
 | 
			
		||||
    osclient_opts = [
 | 
			
		||||
        cfg.StrOpt('os-username',
 | 
			
		||||
                   default=env('OS_USERNAME'),
 | 
			
		||||
                   help='Name used for authentication with the OpenStack '
 | 
			
		||||
                        'Identity service. Defaults to env[OS_USERNAME].',
 | 
			
		||||
                   dest='os_username'),
 | 
			
		||||
        cfg.StrOpt('os-password',
 | 
			
		||||
                   default=env('OS_PASSWORD'),
 | 
			
		||||
                   help='Password used for authentication with the OpenStack '
 | 
			
		||||
                        'Identity service. Defaults to env[OS_PASSWORD].',
 | 
			
		||||
                   dest='os_password'),
 | 
			
		||||
        cfg.StrOpt('os-project-name',
 | 
			
		||||
                   default=env('OS_PROJECT_NAME'),
 | 
			
		||||
                   help='Project name to scope to. Defaults to '
 | 
			
		||||
                        'env[OS_PROJECT_NAME].',
 | 
			
		||||
                   dest='os_project_name'),
 | 
			
		||||
        cfg.StrOpt('os-project-domain-name',
 | 
			
		||||
                   default=env('OS_PROJECT_DOMAIN_NAME'),
 | 
			
		||||
                   help='Domain name containing project. Defaults to '
 | 
			
		||||
                        'env[OS_PROJECT_DOMAIN_NAME].',
 | 
			
		||||
                   dest='os_project_domain_name'),
 | 
			
		||||
        cfg.StrOpt('os-user-domain-name',
 | 
			
		||||
                   default=env('OS_USER_DOMAIN_NAME'),
 | 
			
		||||
                   help='User\'s domain name. Defaults to '
 | 
			
		||||
                        'env[OS_USER_DOMAIN_NAME].',
 | 
			
		||||
                   dest='os_user_domain_name'),
 | 
			
		||||
        cfg.StrOpt('os-tenant-name',
 | 
			
		||||
                   default=env('OS_TENANT_NAME'),
 | 
			
		||||
                   help='Tenant to request authorization on. Defaults to '
 | 
			
		||||
                        'env[OS_TENANT_NAME].',
 | 
			
		||||
                   dest='os_tenant_name'),
 | 
			
		||||
        cfg.StrOpt('os-tenant-id',
 | 
			
		||||
                   default=env('OS_TENANT_ID'),
 | 
			
		||||
                   help='Tenant to request authorization on. Defaults to '
 | 
			
		||||
                        'env[OS_TENANT_ID].',
 | 
			
		||||
                   dest='os_tenant_id'),
 | 
			
		||||
        cfg.StrOpt('os-auth-url',
 | 
			
		||||
                   default=env('OS_AUTH_URL'),
 | 
			
		||||
                   help='Specify the Identity endpoint to use for '
 | 
			
		||||
                        'authentication. Defaults to env[OS_AUTH_URL].',
 | 
			
		||||
                   dest='os_auth_url'),
 | 
			
		||||
        cfg.StrOpt('os-backup-url',
 | 
			
		||||
                   default=env('OS_BACKUP_URL'),
 | 
			
		||||
                   help='Specify the Freezer backup service endpoint to use. '
 | 
			
		||||
                        'Defaults to env[OS_BACKUP_URL].',
 | 
			
		||||
                   dest='os_backup_url'),
 | 
			
		||||
        cfg.StrOpt('os-region-name',
 | 
			
		||||
                   default=env('OS_REGION_NAME'),
 | 
			
		||||
                   help='Specify the region to use. Defaults to '
 | 
			
		||||
                        'env[OS_REGION_NAME].',
 | 
			
		||||
                   dest='os_region_name'),
 | 
			
		||||
        cfg.StrOpt('os-token',
 | 
			
		||||
                   default=env('OS_TOKEN'),
 | 
			
		||||
                   help='Specify an existing token to use instead of retrieving'
 | 
			
		||||
                        ' one via authentication (e.g. with username & '
 | 
			
		||||
                        'password). Defaults to env[OS_TOKEN].',
 | 
			
		||||
                   dest='os_token'),
 | 
			
		||||
        cfg.StrOpt('os-identity-api-version',
 | 
			
		||||
                   default=env('OS_IDENTITY_API_VERSION'),
 | 
			
		||||
                   help='Identity API version: 2.0 or 3. '
 | 
			
		||||
                        'Defaults to env[OS_IDENTITY_API_VERSION]',
 | 
			
		||||
                   dest='os_identity_api_version'),
 | 
			
		||||
        cfg.StrOpt('os-endpoint-type',
 | 
			
		||||
                   choices=['public', 'publicURL', 'internal', 'internalURL',
 | 
			
		||||
                            'admin', 'adminURL'],
 | 
			
		||||
                   default=env('OS_ENDPOINT_TYPE') or 'public',
 | 
			
		||||
                   help='Endpoint type to select. Valid endpoint types: '
 | 
			
		||||
                        '"public" or "publicURL", "internal" or "internalURL",'
 | 
			
		||||
                        ' "admin" or "adminURL". Defaults to '
 | 
			
		||||
                        'env[OS_ENDPOINT_TYPE] or "public"',
 | 
			
		||||
                   dest='os_endpoint_type'),
 | 
			
		||||
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    return osclient_opts
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def guess_auth_version(opts):
 | 
			
		||||
    if opts.os_identity_api_version == '3':
 | 
			
		||||
        return '3'
 | 
			
		||||
    elif opts.os_identity_api_version == '2.0':
 | 
			
		||||
        return '2.0'
 | 
			
		||||
    elif opts.os_auth_url.endswith('v3'):
 | 
			
		||||
        return '3'
 | 
			
		||||
    elif opts.os_auth_url.endswith('v2.0'):
 | 
			
		||||
        return '2.0'
 | 
			
		||||
    raise Exception('Please provide valid keystone auth url with valid'
 | 
			
		||||
                    ' keystone api version to use')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_auth_plugin(opts):
 | 
			
		||||
    auth_version = guess_auth_version(opts)
 | 
			
		||||
    if opts.os_username:
 | 
			
		||||
        if auth_version == '3':
 | 
			
		||||
            return v3.Password(auth_url=opts.os_auth_url,
 | 
			
		||||
                               username=opts.os_username,
 | 
			
		||||
                               password=opts.os_password,
 | 
			
		||||
                               project_name=opts.os_project_name,
 | 
			
		||||
                               user_domain_name=opts.os_user_domain_name,
 | 
			
		||||
                               project_domain_name=opts.os_project_domain_name)
 | 
			
		||||
        elif auth_version == '2.0':
 | 
			
		||||
            return v2.Password(auth_url=opts.os_auth_url,
 | 
			
		||||
                               username=opts.os_username,
 | 
			
		||||
                               password=opts.os_password,
 | 
			
		||||
                               tenant_name=opts.os_tenant_name)
 | 
			
		||||
    elif opts.os_token:
 | 
			
		||||
        if auth_version == '3':
 | 
			
		||||
            return v3.Token(auth_url=opts.os_auth_url,
 | 
			
		||||
                            token=opts.os_token,
 | 
			
		||||
                            project_name=opts.os_project_name,
 | 
			
		||||
                            project_domain_name=opts.os_project_domain_name)
 | 
			
		||||
        elif auth_version == '2.0':
 | 
			
		||||
            return v2.Token(auth_url=opts.os_auth_url,
 | 
			
		||||
                            token=opts.os_token,
 | 
			
		||||
                            tenant_name=opts.os_tenant_name)
 | 
			
		||||
    raise Exception('Unable to determine correct auth method, please provide'
 | 
			
		||||
                    ' either username or token')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Client(object):
 | 
			
		||||
    def __init__(self,
 | 
			
		||||
                 version='1',
 | 
			
		||||
                 token=None,
 | 
			
		||||
                 username=None,
 | 
			
		||||
                 password=None,
 | 
			
		||||
                 tenant_name=None,
 | 
			
		||||
                 auth_url=None,
 | 
			
		||||
                 session=None,
 | 
			
		||||
                 endpoint=None,
 | 
			
		||||
                 opts=None,
 | 
			
		||||
                 project_name=None,
 | 
			
		||||
                 user_domain_name=None,
 | 
			
		||||
                 project_domain_name=None,
 | 
			
		||||
                 verify=True,
 | 
			
		||||
                 cacert=False):
 | 
			
		||||
 | 
			
		||||
        self.opts = opts
 | 
			
		||||
        # this creates a namespace for self.opts when the client is
 | 
			
		||||
        # created from other method rather than command line arguments.
 | 
			
		||||
        if self.opts is None:
 | 
			
		||||
            self.opts = Namespace({})
 | 
			
		||||
        if token:
 | 
			
		||||
            self.opts.os_token = token
 | 
			
		||||
        if username:
 | 
			
		||||
            self.opts.os_username = username
 | 
			
		||||
        if password:
 | 
			
		||||
            self.opts.os_password = password
 | 
			
		||||
        if tenant_name:
 | 
			
		||||
            self.opts.os_tenant_name = tenant_name
 | 
			
		||||
        if auth_url:
 | 
			
		||||
            self.opts.os_auth_url = auth_url
 | 
			
		||||
        if endpoint:
 | 
			
		||||
            self.opts.os_backup_url = endpoint
 | 
			
		||||
        if project_name:
 | 
			
		||||
            self.opts.os_project_name = project_name
 | 
			
		||||
        if user_domain_name:
 | 
			
		||||
            self.opts.os_user_domain_name = user_domain_name
 | 
			
		||||
        if project_domain_name:
 | 
			
		||||
            self.opts.os_project_domain_name = project_domain_name
 | 
			
		||||
 | 
			
		||||
        # flag to initialize freezer-scheduler with insecure mode
 | 
			
		||||
        self.verify = verify
 | 
			
		||||
 | 
			
		||||
        self._session = session
 | 
			
		||||
        self.version = version
 | 
			
		||||
 | 
			
		||||
        self.backups = backups.BackupsManager(self, verify=verify)
 | 
			
		||||
        self.registration = registration.RegistrationManager(self, verify=verify)
 | 
			
		||||
        self.jobs = jobs.JobManager(self, verify=verify)
 | 
			
		||||
        self.actions = actions.ActionManager(self, verify=verify)
 | 
			
		||||
        self.sessions = sessions.SessionManager(self, verify=verify)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @cached_property
 | 
			
		||||
    def session(self):
 | 
			
		||||
        if self._session:
 | 
			
		||||
            return self._session
 | 
			
		||||
        auth_plugin = get_auth_plugin(self.opts)
 | 
			
		||||
        return ksc_session.Session(auth=auth_plugin, verify=self.verify)
 | 
			
		||||
 | 
			
		||||
    @cached_property
 | 
			
		||||
    def endpoint(self):
 | 
			
		||||
        if self.opts.os_backup_url:
 | 
			
		||||
            return self.opts.os_backup_url
 | 
			
		||||
        else:
 | 
			
		||||
            auth_ref = self.session.auth.get_auth_ref(self.session)
 | 
			
		||||
            endpoint = auth_ref.service_catalog.url_for(
 | 
			
		||||
                service_type=FREEZER_SERVICE_TYPE,
 | 
			
		||||
                endpoint_type=self.opts.os_endpoint_type,
 | 
			
		||||
            )
 | 
			
		||||
        return endpoint
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def auth_token(self):
 | 
			
		||||
        return self.session.get_token()
 | 
			
		||||
 | 
			
		||||
    @cached_property
 | 
			
		||||
    def client_id(self):
 | 
			
		||||
        return '{0}_{1}'.format(self.session.get_project_id(),
 | 
			
		||||
                                socket.gethostname())
 | 
			
		||||
							
								
								
									
										0
									
								
								devstack/README.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								devstack/README.rst
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										21
									
								
								devstack/gate_hook.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								devstack/gate_hook.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
set -ex
 | 
			
		||||
 | 
			
		||||
# Install python-freezerclient devstack integration
 | 
			
		||||
export DEVSTACK_LOCAL_CONFIG="enable_plugin python-freezerclient https://git.openstack.org/openstack/python-freezerclient"
 | 
			
		||||
 | 
			
		||||
$BASE/new/devstack-gate/devstack-vm-gate.sh
 | 
			
		||||
							
								
								
									
										43
									
								
								devstack/lib/freezerclient
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								devstack/lib/freezerclient
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
# Install python-freezerclient
 | 
			
		||||
 | 
			
		||||
# add the following to localrc:
 | 
			
		||||
#   enable_service python-freezerclient
 | 
			
		||||
#
 | 
			
		||||
# Dependencies:
 | 
			
		||||
# - functions
 | 
			
		||||
# - OS_AUTH_URL for auth in api
 | 
			
		||||
# - DEST set to the destination directory
 | 
			
		||||
# - SERVICE_PASSWORD, SERVICE_TENANT_NAME for auth in api
 | 
			
		||||
# - STACK_USER service user
 | 
			
		||||
 | 
			
		||||
# Save trace setting
 | 
			
		||||
XTRACE=$(set +o | grep xtrace)
 | 
			
		||||
set +o xtrace
 | 
			
		||||
 | 
			
		||||
# Functions
 | 
			
		||||
# ---------
 | 
			
		||||
 | 
			
		||||
function install_python-freezerclient {
 | 
			
		||||
 | 
			
		||||
    git_clone $FREEZERCLIENT_REPO $FREEZERCLIENT_DIR $FREEZERCLIENT_BRANCH
 | 
			
		||||
    setup_develop $FREEZER_DIR
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Restore xtrace
 | 
			
		||||
$XTRACE
 | 
			
		||||
							
								
								
									
										31
									
								
								devstack/local.conf.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								devstack/local.conf.example
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
[[local|localrc]]
 | 
			
		||||
disable_all_services
 | 
			
		||||
 | 
			
		||||
enable_plugin python-freezerclient https://git.openstack.org/openstack/python-freezerclient master
 | 
			
		||||
 | 
			
		||||
enable_service rabbit mysql key
 | 
			
		||||
 | 
			
		||||
# This is to keep the token small for testing
 | 
			
		||||
KEYSTONE_TOKEN_FORMAT=UUID
 | 
			
		||||
 | 
			
		||||
# Modify passwords as needed
 | 
			
		||||
DATABASE_PASSWORD=secretdatabase
 | 
			
		||||
RABBIT_PASSWORD=secretrabbit
 | 
			
		||||
ADMIN_PASSWORD=secretadmin
 | 
			
		||||
SERVICE_PASSWORD=secretservice
 | 
			
		||||
SERVICE_TOKEN=111222333444
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								devstack/plugin.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								devstack/plugin.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
# check for service enabled
 | 
			
		||||
if is_service_enabled python-freezerclient; then
 | 
			
		||||
    if [[ "$1" == "source" || "`type -t install_freezerclient`" != 'function' ]]; then
 | 
			
		||||
        # Initial source
 | 
			
		||||
        source $FREEZER_DIR/devstack/lib/python-freezerclient
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ "$1" == "stack" && "$2" == "install" ]]; then
 | 
			
		||||
        echo_summary "Installing python-freezerclient"
 | 
			
		||||
        install_freezerclient
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								devstack/settings
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								devstack/settings
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
# Defaults
 | 
			
		||||
# --------
 | 
			
		||||
 | 
			
		||||
# Set up default directories
 | 
			
		||||
FREEZERCLIENT_DIR=$DEST/python-freezerclient
 | 
			
		||||
FREEZERCLIENT_LOG_DIR=$DEST/logs
 | 
			
		||||
 | 
			
		||||
# Python freezerclient repository
 | 
			
		||||
FREEZERCLIENT_REPO=${FREEZER_REPO:-${GIT_BASE}/openstack/python-freezerclient.git}
 | 
			
		||||
FREEZERCLIENT_BRANCH=${FREEZER_BRANCH:-master}
 | 
			
		||||
 | 
			
		||||
enable_service python-freezerclient
 | 
			
		||||
							
								
								
									
										3
									
								
								doc/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								doc/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
build/
 | 
			
		||||
source/ref/
 | 
			
		||||
source/api/
 | 
			
		||||
							
								
								
									
										265
									
								
								doc/source/conf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								doc/source/conf.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,265 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
#
 | 
			
		||||
# Freezer documentation build configuration file, created by
 | 
			
		||||
# sphinx-quickstart on Thu Feb  4 22:27:35 2016.
 | 
			
		||||
#
 | 
			
		||||
# This file is execfile()d with the current directory set to its
 | 
			
		||||
# containing dir.
 | 
			
		||||
#
 | 
			
		||||
# Note that not all possible configuration values are present in this
 | 
			
		||||
# autogenerated file.
 | 
			
		||||
#
 | 
			
		||||
# All configuration values have a default; values that are commented out
 | 
			
		||||
# serve to show the default.
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
# If extensions (or modules to document with autodoc) are in another directory,
 | 
			
		||||
# add these directories to sys.path here. If the directory is relative to the
 | 
			
		||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
 | 
			
		||||
#sys.path.insert(0, os.path.abspath('.'))
 | 
			
		||||
 | 
			
		||||
# -- General configuration ------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# If your documentation needs a minimal Sphinx version, state it here.
 | 
			
		||||
#needs_sphinx = '1.0'
 | 
			
		||||
 | 
			
		||||
# Add any Sphinx extension module names here, as strings. They can be
 | 
			
		||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 | 
			
		||||
# ones.
 | 
			
		||||
extensions = ['sphinx.ext.autodoc',
 | 
			
		||||
              'sphinx.ext.viewcode',
 | 
			
		||||
              'oslosphinx']
 | 
			
		||||
 | 
			
		||||
# Add any paths that contain templates here, relative to this directory.
 | 
			
		||||
templates_path = ['_templates']
 | 
			
		||||
 | 
			
		||||
# The suffix of source filenames.
 | 
			
		||||
source_suffix = '.rst'
 | 
			
		||||
 | 
			
		||||
# The encoding of source files.
 | 
			
		||||
#source_encoding = 'utf-8-sig'
 | 
			
		||||
 | 
			
		||||
# The master toctree document.
 | 
			
		||||
master_doc = 'index'
 | 
			
		||||
 | 
			
		||||
# General information about the project.
 | 
			
		||||
project = u'Python Freezer Client'
 | 
			
		||||
copyright = u'2016, OpenStack'
 | 
			
		||||
 | 
			
		||||
# The version info for the project you're documenting, acts as replacement for
 | 
			
		||||
# |version| and |release|, also used in various other places throughout the
 | 
			
		||||
# built documents.
 | 
			
		||||
#
 | 
			
		||||
# The short X.Y version.
 | 
			
		||||
version = '2.0'
 | 
			
		||||
# The full version, including alpha/beta/rc tags.
 | 
			
		||||
release = '2.0.0'
 | 
			
		||||
 | 
			
		||||
# The language for content autogenerated by Sphinx. Refer to documentation
 | 
			
		||||
# for a list of supported languages.
 | 
			
		||||
#language = None
 | 
			
		||||
 | 
			
		||||
# There are two options for replacing |today|: either, you set today to some
 | 
			
		||||
# non-false value, then it is used:
 | 
			
		||||
#today = ''
 | 
			
		||||
# Else, today_fmt is used as the format for a strftime call.
 | 
			
		||||
#today_fmt = '%B %d, %Y'
 | 
			
		||||
 | 
			
		||||
# List of patterns, relative to source directory, that match files and
 | 
			
		||||
# directories to ignore when looking for source files.
 | 
			
		||||
exclude_patterns = []
 | 
			
		||||
 | 
			
		||||
# The reST default role (used for this markup: `text`) to use for all
 | 
			
		||||
# documents.
 | 
			
		||||
#default_role = None
 | 
			
		||||
 | 
			
		||||
# If true, '()' will be appended to :func: etc. cross-reference text.
 | 
			
		||||
#add_function_parentheses = True
 | 
			
		||||
 | 
			
		||||
# If true, the current module name will be prepended to all description
 | 
			
		||||
# unit titles (such as .. function::).
 | 
			
		||||
#add_module_names = True
 | 
			
		||||
 | 
			
		||||
# If true, sectionauthor and moduleauthor directives will be shown in the
 | 
			
		||||
# output. They are ignored by default.
 | 
			
		||||
#show_authors = False
 | 
			
		||||
 | 
			
		||||
# The name of the Pygments (syntax highlighting) style to use.
 | 
			
		||||
pygments_style = 'sphinx'
 | 
			
		||||
 | 
			
		||||
# A list of ignored prefixes for module index sorting.
 | 
			
		||||
#modindex_common_prefix = []
 | 
			
		||||
 | 
			
		||||
# If true, keep warnings as "system message" paragraphs in the built documents.
 | 
			
		||||
#keep_warnings = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- Options for HTML output ----------------------------------------------
 | 
			
		||||
 | 
			
		||||
# The theme to use for HTML and HTML Help pages.  See the documentation for
 | 
			
		||||
# a list of builtin themes.
 | 
			
		||||
html_theme = 'default'
 | 
			
		||||
 | 
			
		||||
# Theme options are theme-specific and customize the look and feel of a theme
 | 
			
		||||
# further.  For a list of options available for each theme, see the
 | 
			
		||||
# documentation.
 | 
			
		||||
#html_theme_options = {}
 | 
			
		||||
 | 
			
		||||
# Add any paths that contain custom themes here, relative to this directory.
 | 
			
		||||
#html_theme_path = []
 | 
			
		||||
 | 
			
		||||
# The name for this set of Sphinx documents.  If None, it defaults to
 | 
			
		||||
# "<project> v<release> documentation".
 | 
			
		||||
#html_title = None
 | 
			
		||||
 | 
			
		||||
# A shorter title for the navigation bar.  Default is the same as html_title.
 | 
			
		||||
#html_short_title = None
 | 
			
		||||
 | 
			
		||||
# The name of an image file (relative to this directory) to place at the top
 | 
			
		||||
# of the sidebar.
 | 
			
		||||
#html_logo = None
 | 
			
		||||
 | 
			
		||||
# The name of an image file (within the static path) to use as favicon of the
 | 
			
		||||
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
 | 
			
		||||
# pixels large.
 | 
			
		||||
#html_favicon = None
 | 
			
		||||
 | 
			
		||||
# Add any paths that contain custom static files (such as style sheets) here,
 | 
			
		||||
# relative to this directory. They are copied after the builtin static files,
 | 
			
		||||
# so a file named "default.css" will overwrite the builtin "default.css".
 | 
			
		||||
html_static_path = ['_static']
 | 
			
		||||
 | 
			
		||||
# Add any extra paths that contain custom files (such as robots.txt or
 | 
			
		||||
# .htaccess) here, relative to this directory. These files are copied
 | 
			
		||||
# directly to the root of the documentation.
 | 
			
		||||
#html_extra_path = []
 | 
			
		||||
 | 
			
		||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 | 
			
		||||
# using the given strftime format.
 | 
			
		||||
#html_last_updated_fmt = '%b %d, %Y'
 | 
			
		||||
 | 
			
		||||
# If true, SmartyPants will be used to convert quotes and dashes to
 | 
			
		||||
# typographically correct entities.
 | 
			
		||||
#html_use_smartypants = True
 | 
			
		||||
 | 
			
		||||
# Custom sidebar templates, maps document names to template names.
 | 
			
		||||
#html_sidebars = {}
 | 
			
		||||
 | 
			
		||||
# Additional templates that should be rendered to pages, maps page names to
 | 
			
		||||
# template names.
 | 
			
		||||
#html_additional_pages = {}
 | 
			
		||||
 | 
			
		||||
# If false, no module index is generated.
 | 
			
		||||
#html_domain_indices = True
 | 
			
		||||
 | 
			
		||||
# If false, no index is generated.
 | 
			
		||||
#html_use_index = True
 | 
			
		||||
 | 
			
		||||
# If true, the index is split into individual pages for each letter.
 | 
			
		||||
#html_split_index = False
 | 
			
		||||
 | 
			
		||||
# If true, links to the reST sources are added to the pages.
 | 
			
		||||
#html_show_sourcelink = True
 | 
			
		||||
 | 
			
		||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
 | 
			
		||||
#html_show_sphinx = True
 | 
			
		||||
 | 
			
		||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
 | 
			
		||||
#html_show_copyright = True
 | 
			
		||||
 | 
			
		||||
# If true, an OpenSearch description file will be output, and all pages will
 | 
			
		||||
# contain a <link> tag referring to it.  The value of this option must be the
 | 
			
		||||
# base URL from which the finished HTML is served.
 | 
			
		||||
#html_use_opensearch = ''
 | 
			
		||||
 | 
			
		||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
 | 
			
		||||
#html_file_suffix = None
 | 
			
		||||
 | 
			
		||||
# Output file base name for HTML help builder.
 | 
			
		||||
htmlhelp_basename = 'Freezerdoc'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- Options for LaTeX output ---------------------------------------------
 | 
			
		||||
 | 
			
		||||
latex_elements = {
 | 
			
		||||
# The paper size ('letterpaper' or 'a4paper').
 | 
			
		||||
#'papersize': 'letterpaper',
 | 
			
		||||
 | 
			
		||||
# The font size ('10pt', '11pt' or '12pt').
 | 
			
		||||
#'pointsize': '10pt',
 | 
			
		||||
 | 
			
		||||
# Additional stuff for the LaTeX preamble.
 | 
			
		||||
#'preamble': '',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Grouping the document tree into LaTeX files. List of tuples
 | 
			
		||||
# (source start file, target name, title,
 | 
			
		||||
#  author, documentclass [howto, manual, or own class]).
 | 
			
		||||
latex_documents = [
 | 
			
		||||
  ('index', 'Freezer.tex', u'Freezer Documentation',
 | 
			
		||||
   u'OpenStack', 'manual'),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# The name of an image file (relative to this directory) to place at the top of
 | 
			
		||||
# the title page.
 | 
			
		||||
#latex_logo = None
 | 
			
		||||
 | 
			
		||||
# For "manual" documents, if this is true, then toplevel headings are parts,
 | 
			
		||||
# not chapters.
 | 
			
		||||
#latex_use_parts = False
 | 
			
		||||
 | 
			
		||||
# If true, show page references after internal links.
 | 
			
		||||
#latex_show_pagerefs = False
 | 
			
		||||
 | 
			
		||||
# If true, show URL addresses after external links.
 | 
			
		||||
#latex_show_urls = False
 | 
			
		||||
 | 
			
		||||
# Documents to append as an appendix to all manuals.
 | 
			
		||||
#latex_appendices = []
 | 
			
		||||
 | 
			
		||||
# If false, no module index is generated.
 | 
			
		||||
#latex_domain_indices = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- Options for manual page output ---------------------------------------
 | 
			
		||||
 | 
			
		||||
# One entry per manual page. List of tuples
 | 
			
		||||
# (source start file, name, description, authors, manual section).
 | 
			
		||||
man_pages = [
 | 
			
		||||
    ('index', 'freezer', u'Freezer Documentation',
 | 
			
		||||
     [u'OpenStack'], 1)
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# If true, show URL addresses after external links.
 | 
			
		||||
#man_show_urls = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- Options for Texinfo output -------------------------------------------
 | 
			
		||||
 | 
			
		||||
# Grouping the document tree into Texinfo files. List of tuples
 | 
			
		||||
# (source start file, target name, title, author,
 | 
			
		||||
#  dir menu entry, description, category)
 | 
			
		||||
texinfo_documents = [
 | 
			
		||||
  ('index', 'Freezer', u'Freezer Documentation',
 | 
			
		||||
   u'OpenStack', 'Freezer', 'One line description of project.',
 | 
			
		||||
   'Miscellaneous'),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# Documents to append as an appendix to all manuals.
 | 
			
		||||
#texinfo_appendices = []
 | 
			
		||||
 | 
			
		||||
# If false, no module index is generated.
 | 
			
		||||
#texinfo_domain_indices = True
 | 
			
		||||
 | 
			
		||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
 | 
			
		||||
#texinfo_show_urls = 'footnote'
 | 
			
		||||
 | 
			
		||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
 | 
			
		||||
#texinfo_no_detailmenu = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Example configuration for intersphinx: refer to the Python standard library.
 | 
			
		||||
#intersphinx_mapping = {'http://docs.python.org/': None}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								doc/source/index.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								doc/source/index.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
.. Python Freezer Client documentation master file, created by
 | 
			
		||||
   sphinx-quickstart on Thu Feb  4 22:27:35 2016.
 | 
			
		||||
   You can adapt this file completely to your liking, but it should at least
 | 
			
		||||
   contain the root `toctree` directive.
 | 
			
		||||
 | 
			
		||||
Welcome to Freezer's documentation!
 | 
			
		||||
===================================
 | 
			
		||||
 | 
			
		||||
Contents:
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Indices and tables
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
* :ref:`genindex`
 | 
			
		||||
* :ref:`modindex`
 | 
			
		||||
* :ref:`search`
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										0
									
								
								freezerclient/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								freezerclient/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -1,19 +1,16 @@
 | 
			
		||||
"""
 | 
			
		||||
(c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										234
									
								
								freezerclient/shell.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								freezerclient/shell.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,234 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from cliff.app import App
 | 
			
		||||
from cliff.commandmanager import CommandManager
 | 
			
		||||
 | 
			
		||||
from freezerclient.v1 import actions
 | 
			
		||||
from freezerclient.v1 import backups
 | 
			
		||||
from freezerclient.v1.client import Client
 | 
			
		||||
from freezerclient.v1 import clients
 | 
			
		||||
from freezerclient.v1 import jobs
 | 
			
		||||
from freezerclient.v1 import sessions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FreezerCommandManager(CommandManager):
 | 
			
		||||
    """ All commands available for the shell are registered here """
 | 
			
		||||
    SHELL_COMMANDS = {
 | 
			
		||||
        'job-show': jobs.JobShow,
 | 
			
		||||
        'job-list': jobs.JobList,
 | 
			
		||||
        'job-create': jobs.JobCreate,
 | 
			
		||||
        'job-get': jobs.JobGet,
 | 
			
		||||
        'job-delete': jobs.JobDelete,
 | 
			
		||||
        'job-start': jobs.JobStart,
 | 
			
		||||
        'job-stop': jobs.JobStop,
 | 
			
		||||
        'job-abort': jobs.JobAbort,
 | 
			
		||||
        'job-update': jobs.JobUpdate,
 | 
			
		||||
        'client-list': clients.ClientList,
 | 
			
		||||
        'client-show': clients.ClientShow,
 | 
			
		||||
        'client-register': clients.ClientRegister,
 | 
			
		||||
        'client-delete': clients.ClientDelete,
 | 
			
		||||
        'backup-list': backups.BackupList,
 | 
			
		||||
        'backup-show': backups.BackupShow,
 | 
			
		||||
        'session-list': sessions.SessionList,
 | 
			
		||||
        'session-show': sessions.SessionShow,
 | 
			
		||||
        'session-create': sessions.SessionCreate,
 | 
			
		||||
        'session-add-job': sessions.SessionAddJob,
 | 
			
		||||
        'session-remove-job': sessions.SessionRemoveJob,
 | 
			
		||||
        'session-start': sessions.SessionStart,
 | 
			
		||||
        'session-end': sessions.SessionEnd,
 | 
			
		||||
        'session-update': sessions.SessionUpdate,
 | 
			
		||||
        'action-show': actions.ActionShow,
 | 
			
		||||
        'action-list': actions.ActionList,
 | 
			
		||||
        'action-delete': actions.ActionDelete,
 | 
			
		||||
        'action-create': actions.ActionCreate,
 | 
			
		||||
        'action-update': actions.ActionUpdate
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    def load_commands(self, namespace):
 | 
			
		||||
        for name, command_class in self.SHELL_COMMANDS.items():
 | 
			
		||||
            self.add_command(name, command_class)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FreezerShell(App):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        super(FreezerShell, self).__init__(
 | 
			
		||||
            description='Python Freezer Client',
 | 
			
		||||
            version='0.1',
 | 
			
		||||
            deferred_help=True,
 | 
			
		||||
            command_manager=FreezerCommandManager(None),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def build_option_parser(self, description, version):
 | 
			
		||||
        parser = super(FreezerShell, self).build_option_parser(description, version)
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-auth-url',
 | 
			
		||||
            dest='os_auth_url',
 | 
			
		||||
            default=os.environ.get('OS_AUTH_URL'),
 | 
			
		||||
            help='Specify identity endpoint',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-backup-url',
 | 
			
		||||
            dest='os_backup_url',
 | 
			
		||||
            default=os.environ.get('OS_BACKUP_URL'),
 | 
			
		||||
            help='Specify the Freezer backup service endpoint to use'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-endpoint-type',
 | 
			
		||||
            dest='os_endpoint_type',
 | 
			
		||||
            default=os.environ.get('OS_ENDPOINT_TYPE'),
 | 
			
		||||
            help='''Endpoint type to select. Valid endpoint types:
 | 
			
		||||
                    "public" or "publicURL", "internal" or "internalURL",
 | 
			
		||||
                    "admin" or "adminURL"'''
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-identity-api-version',
 | 
			
		||||
            dest='os_identity_api_version',
 | 
			
		||||
            default=os.environ.get('OS_IDENTITY_API_VERSION'),
 | 
			
		||||
            help='Identity API version: 2.0 or 3'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-password',
 | 
			
		||||
            dest='os_password',
 | 
			
		||||
            default=os.environ.get('OS_PASSWORD'),
 | 
			
		||||
            help='''Password used for authentication with the OpenStack
 | 
			
		||||
                    Identity service'''
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-username',
 | 
			
		||||
            dest='os_username',
 | 
			
		||||
            default=os.environ.get('OS_USERNAME'),
 | 
			
		||||
            help='''Name used for authentication with the OpenStack
 | 
			
		||||
                    Identity service'''
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-token',
 | 
			
		||||
            dest='os_token',
 | 
			
		||||
            default=os.environ.get('OS_TOKEN'),
 | 
			
		||||
            help='''Specify an existing token to use instead of retrieving
 | 
			
		||||
                    one via authentication'''
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-project-domain-name',
 | 
			
		||||
            dest='os_project_domain_name',
 | 
			
		||||
            default=os.environ.get('OS_PROJECT_DOMAIN_NAME'),
 | 
			
		||||
            help='Domain name containing project'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-project-name',
 | 
			
		||||
            dest='os_project_name',
 | 
			
		||||
            default=os.environ.get('OS_PROJECT_NAME'),
 | 
			
		||||
            help='Project name to scope to'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-region-name',
 | 
			
		||||
            dest='os_region_name',
 | 
			
		||||
            default=os.environ.get('OS_REGION_NAME'),
 | 
			
		||||
            help='Specify the region to use'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-tenant-id',
 | 
			
		||||
            dest='os_tenant_id',
 | 
			
		||||
            default=os.environ.get('OS_TENANT_ID'),
 | 
			
		||||
            help='Tenant to request authorization on'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-tenant-name',
 | 
			
		||||
            dest='os_tenant_name',
 | 
			
		||||
            default=os.environ.get('OS_TENANT_NAME'),
 | 
			
		||||
            help='Tenant to request authorization on'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-user-domain-name',
 | 
			
		||||
            dest='os_user_domain_name',
 | 
			
		||||
            default=os.environ.get('OS_USER_DOMAIN_NAME'),
 | 
			
		||||
            help='User domain name'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '-k', '--insecure',
 | 
			
		||||
            dest='insecure',
 | 
			
		||||
            action='store_true',
 | 
			
		||||
            default=os.environ.get('OS_INSECURE'),
 | 
			
		||||
            help='use python-freezerclient with insecure connections'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-cacert',
 | 
			
		||||
            dest='os_cacert',
 | 
			
		||||
            default=os.environ.get('OS_CACERT'),
 | 
			
		||||
            help='''Path of CA TLS certificate(s) used to verify the
 | 
			
		||||
                    remote server's certificate. Without this option
 | 
			
		||||
                    freezer looks for the default system CA certificates.'''
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--os-cert',
 | 
			
		||||
            dest='os_cert',
 | 
			
		||||
            default=os.environ.get('OS_CERT'),
 | 
			
		||||
            help='''Path of CERT TLS certificate(s) used to verify the
 | 
			
		||||
                    remote server's certificate.1'''
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def client(self):
 | 
			
		||||
        """ Build a client object to communicate with the API
 | 
			
		||||
        :return: freezerclient object
 | 
			
		||||
        """
 | 
			
		||||
        opts = {
 | 
			
		||||
            'token': self.options.os_token,
 | 
			
		||||
            'version': self.options.os_identity_api_version,
 | 
			
		||||
            'username': self.options.os_username,
 | 
			
		||||
            'password': self.options.os_password,
 | 
			
		||||
            'tenant_name': self.options.os_tenant_name,
 | 
			
		||||
            'auth_url': self.options.os_auth_url,
 | 
			
		||||
            'endpoint': self.options.os_backup_url,
 | 
			
		||||
            'project_name': self.options.os_project_name,
 | 
			
		||||
            'user_domain_name': self.options.os_user_domain_name,
 | 
			
		||||
            'project_domain_name': self.options.os_project_domain_name,
 | 
			
		||||
            'verify': True or self.options.os_cacert,
 | 
			
		||||
            'cert': self.options.os_cert
 | 
			
		||||
        }
 | 
			
		||||
        return Client(**opts)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main(argv=sys.argv[1:]):
 | 
			
		||||
    print('hola') 
 | 
			
		||||
    return FreezerShell().run(argv)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    sys.exit(main(sys.argv[1:]))
 | 
			
		||||
							
								
								
									
										0
									
								
								freezerclient/tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								freezerclient/tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								freezerclient/tests/unit/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								freezerclient/tests/unit/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										25
									
								
								freezerclient/tests/unit/test_exceptions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								freezerclient/tests/unit/test_exceptions.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestApiClientException(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_get_message_from_response_string(self):
 | 
			
		||||
        e = exceptions.ApiClientException('some error message')
 | 
			
		||||
        self.assertEquals(str(e), 'some error message')
 | 
			
		||||
							
								
								
									
										13
									
								
								freezerclient/tests/unit/test_utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								freezerclient/tests/unit/test_utils.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
							
								
								
									
										0
									
								
								freezerclient/tests/unit/v1/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								freezerclient/tests/unit/v1/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										150
									
								
								freezerclient/tests/unit/v1/test_client.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								freezerclient/tests/unit/v1/test_client.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
			
		||||
# (c) Copyright 2014,2015,2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from freezerclient.v1 import client
 | 
			
		||||
 | 
			
		||||
from mock import Mock, patch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestSupportFunctions(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_guess_auth_version_returns_none(self):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_identity_api_version = ''
 | 
			
		||||
        mock_opts.os_auth_url = ''
 | 
			
		||||
        self.assertRaises(Exception, client.guess_auth_version, mock_opts)
 | 
			
		||||
 | 
			
		||||
    def test_guess_auth_version_explicit_3(self):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_identity_api_version = '3'
 | 
			
		||||
        self.assertEquals(client.guess_auth_version(mock_opts), '3')
 | 
			
		||||
 | 
			
		||||
    def test_guess_auth_version_explicit_2(self):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_identity_api_version = '2.0'
 | 
			
		||||
        self.assertEquals(client.guess_auth_version(mock_opts), '2.0')
 | 
			
		||||
 | 
			
		||||
    def test_guess_auth_version_implicit_3(self):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_auth_url = 'http://whatever/v3'
 | 
			
		||||
        self.assertEquals(client.guess_auth_version(mock_opts), '3')
 | 
			
		||||
 | 
			
		||||
    def test_guess_auth_version_implicit_2(self):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_auth_url = 'http://whatever/v2.0'
 | 
			
		||||
        self.assertEquals(client.guess_auth_version(mock_opts), '2.0')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.client.v3')
 | 
			
		||||
    @patch('freezerclient.v1.client.v2')
 | 
			
		||||
    def test_get_auth_plugin_v3_Password(self, mock_v2, mock_v3):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_identity_api_version = '3'
 | 
			
		||||
        mock_opts.os_user_name = 'myuser'
 | 
			
		||||
        mock_opts.os_token = ''
 | 
			
		||||
        client.get_auth_plugin(mock_opts)
 | 
			
		||||
        self.assertTrue(mock_v3.Password.called)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.client.v3')
 | 
			
		||||
    @patch('freezerclient.v1.client.v2')
 | 
			
		||||
    def test_get_auth_plugin_v3_Token(self, mock_v2, mock_v3):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_identity_api_version = '3'
 | 
			
		||||
        mock_opts.os_username = ''
 | 
			
		||||
        mock_opts.os_token = 'mytoken'
 | 
			
		||||
        client.get_auth_plugin(mock_opts)
 | 
			
		||||
        self.assertTrue(mock_v3.Token.called)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.client.v3')
 | 
			
		||||
    @patch('freezerclient.v1.client.v2')
 | 
			
		||||
    def test_get_auth_plugin_v2_Password(self, mock_v2, mock_v3):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_identity_api_version = '2.0'
 | 
			
		||||
        mock_opts.os_user_name = 'myuser'
 | 
			
		||||
        mock_opts.os_token = ''
 | 
			
		||||
        client.get_auth_plugin(mock_opts)
 | 
			
		||||
        self.assertTrue(mock_v2.Password.called)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.client.v3')
 | 
			
		||||
    @patch('freezerclient.v1.client.v2')
 | 
			
		||||
    def test_get_auth_plugin_v2_Token(self, mock_v2, mock_v3):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_identity_api_version = '2.0'
 | 
			
		||||
        mock_opts.os_username = ''
 | 
			
		||||
        mock_opts.os_token = 'mytoken'
 | 
			
		||||
        client.get_auth_plugin(mock_opts)
 | 
			
		||||
        self.assertTrue(mock_v2.Token.called)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.client.v3')
 | 
			
		||||
    @patch('freezerclient.v1.client.v2')
 | 
			
		||||
    def test_get_auth_plugin_raises_when_no_username_token(self, mock_v2, mock_v3):
 | 
			
		||||
        mock_opts = Mock()
 | 
			
		||||
        mock_opts.os_identity_api_version = '2.0'
 | 
			
		||||
        mock_opts.os_username = ''
 | 
			
		||||
        mock_opts.os_token = ''
 | 
			
		||||
        self.assertRaises(Exception, client.get_auth_plugin, mock_opts)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestClientMock(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.client.ksc_session')
 | 
			
		||||
    @patch('freezerclient.v1.client.get_auth_plugin')
 | 
			
		||||
    def test_client_new(self, mock_get_auth_plugin, mock_ksc_session):
 | 
			
		||||
        c = client.Client(opts=Mock(), endpoint='blabla')
 | 
			
		||||
        self.assertIsInstance(c, client.Client)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.client.ksc_session')
 | 
			
		||||
    @patch('freezerclient.v1.client.get_auth_plugin')
 | 
			
		||||
    def test_client_new_with_kwargs(self, mock_get_auth_plugin, mock_ksc_session):
 | 
			
		||||
        kwargs = {'token': 'alpha',
 | 
			
		||||
                  'username': 'bravo',
 | 
			
		||||
                  'password': 'charlie',
 | 
			
		||||
                  'tenant_name': 'delta',
 | 
			
		||||
                  'auth_url': 'echo',
 | 
			
		||||
                  'session': 'foxtrot',
 | 
			
		||||
                  'endpoint': 'golf',
 | 
			
		||||
                  'version': 'hotel',
 | 
			
		||||
                  'opts': Mock()}
 | 
			
		||||
        c = client.Client(**kwargs)
 | 
			
		||||
        self.assertIsInstance(c, client.Client)
 | 
			
		||||
        self.assertEqual('alpha', c.opts.os_token)
 | 
			
		||||
        self.assertEqual('bravo', c.opts.os_username)
 | 
			
		||||
        self.assertEqual('charlie', c.opts.os_password)
 | 
			
		||||
        self.assertEqual('delta', c.opts.os_tenant_name)
 | 
			
		||||
        self.assertEqual('echo', c.opts.os_auth_url)
 | 
			
		||||
        self.assertEqual('foxtrot', c._session)
 | 
			
		||||
        self.assertEqual('foxtrot', c.session)
 | 
			
		||||
        self.assertEqual('golf', c.endpoint)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.client.ksc_session')
 | 
			
		||||
    @patch('freezerclient.v1.client.get_auth_plugin')
 | 
			
		||||
    def test_get_token(self, mock_get_auth_plugin, mock_ksc_session):
 | 
			
		||||
        mock_session = Mock()
 | 
			
		||||
        mock_session.get_token.return_value = 'antaniX2'
 | 
			
		||||
        c = client.Client(session=mock_session, endpoint='justtest', opts=Mock())
 | 
			
		||||
        self.assertIsInstance(c, client.Client)
 | 
			
		||||
        self.assertEquals(c.auth_token, 'antaniX2')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.client.socket')
 | 
			
		||||
    @patch('freezerclient.v1.client.ksc_session')
 | 
			
		||||
    @patch('freezerclient.v1.client.get_auth_plugin')
 | 
			
		||||
    def test_get_client_id(self, mock_get_auth_plugin, mock_ksc_session, mock_socket):
 | 
			
		||||
        mock_socket.gethostname.return_value = 'parmenide'
 | 
			
		||||
        mock_session = Mock()
 | 
			
		||||
        mock_session.get_project_id.return_value = 'H2O'
 | 
			
		||||
        c = client.Client(session=mock_session, endpoint='justtest', opts=Mock())
 | 
			
		||||
        self.assertIsInstance(c, client.Client)
 | 
			
		||||
        self.assertEquals(c.client_id, 'H2O_parmenide')
 | 
			
		||||
							
								
								
									
										128
									
								
								freezerclient/tests/unit/v1/test_client_actions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								freezerclient/tests/unit/v1/test_client_actions.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
# (c) Copyright 2014,2015,2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
from freezerclient.v1.managers import actions
 | 
			
		||||
 | 
			
		||||
from mock import Mock, patch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestActionManager(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.mock_client = Mock()
 | 
			
		||||
        self.mock_response = Mock()
 | 
			
		||||
        self.mock_client.endpoint = 'http://testendpoint:9999'
 | 
			
		||||
        self.mock_client.auth_token = 'testtoken'
 | 
			
		||||
        self.mock_client.client_id = 'test_client_id_78900987'
 | 
			
		||||
        self.action_manager = actions.ActionManager(self.mock_client)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_create(self, mock_requests):
 | 
			
		||||
        self.assertEqual('http://testendpoint:9999/v1/actions/', self.action_manager.endpoint)
 | 
			
		||||
        self.assertEqual({'X-Auth-Token': 'testtoken'}, self.action_manager.headers)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_create_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 201
 | 
			
		||||
        self.mock_response.json.return_value = {'action_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        retval = self.action_manager.create({'action': 'metadata'})
 | 
			
		||||
        self.assertEqual('qwerqwer', retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_create_fail_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.action_manager.create, {'action': 'metadata'})
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_delete_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 204
 | 
			
		||||
        mock_requests.delete.return_value = self.mock_response
 | 
			
		||||
        retval = self.action_manager.delete('test_action_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_delete_fail(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.delete.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.action_manager.delete, 'test_action_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_get_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 200
 | 
			
		||||
        self.mock_response.json.return_value = {'action_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        retval = self.action_manager.get('test_action_id')
 | 
			
		||||
        self.assertEqual({'action_id': 'qwerqwer'}, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_get_fails_on_error_different_from_404(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.action_manager.get, 'test_action_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_get_none(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 404
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        retval = self.action_manager.get('test_action_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_list_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 200
 | 
			
		||||
        action_list = [{'action_id_0': 'bomboloid'}, {'action_id_1': 'asdfasdf'}]
 | 
			
		||||
        self.mock_response.json.return_value = {'actions': action_list}
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        retval = self.action_manager.list()
 | 
			
		||||
        self.assertEqual(action_list, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_list_error(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 404
 | 
			
		||||
        action_list = [{'action_id_0': 'bomboloid'}, {'action_id_1': 'asdfasdf'}]
 | 
			
		||||
        self.mock_response.json.return_value = {'clients': action_list}
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.action_manager.list)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_update_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 200
 | 
			
		||||
        self.mock_response.json.return_value = {
 | 
			
		||||
            "patch": {"status": "bamboozled"},
 | 
			
		||||
            "version": 12,
 | 
			
		||||
            "action_id": "d454beec-1f3c-4d11-aa1a-404116a40502"
 | 
			
		||||
        }
 | 
			
		||||
        mock_requests.patch.return_value = self.mock_response
 | 
			
		||||
        retval = self.action_manager.update('d454beec-1f3c-4d11-aa1a-404116a40502', {'status': 'bamboozled'})
 | 
			
		||||
        self.assertEqual(12, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.actions.requests')
 | 
			
		||||
    def test_update_raise_MetadataUpdateFailure_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        self.mock_response.json.return_value = {
 | 
			
		||||
            "patch": {"status": "bamboozled"},
 | 
			
		||||
            "version": 12,
 | 
			
		||||
            "action_id": "d454beec-1f3c-4d11-aa1a-404116a40502"
 | 
			
		||||
        }
 | 
			
		||||
        self.mock_response.status_code = 404
 | 
			
		||||
        self.mock_response.text = '{"title": "Not Found","description":"No document found with ID d454beec-1f3c-4d11-aa1a-404116a40502x"}'
 | 
			
		||||
        mock_requests.patch.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.action_manager.update,
 | 
			
		||||
                          'd454beec-1f3c-4d11-aa1a-404116a40502', {'status': 'bamboozled'})
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										129
									
								
								freezerclient/tests/unit/v1/test_client_backups.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								freezerclient/tests/unit/v1/test_client_backups.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
# (c) Copyright 2014,2015,2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
from freezerclient.v1.managers import backups
 | 
			
		||||
 | 
			
		||||
from mock import Mock, patch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestBackupManager(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.mock_client = Mock()
 | 
			
		||||
        self.mock_client.endpoint = 'http://testendpoint:9999'
 | 
			
		||||
        self.mock_client.auth_token = 'testtoken'
 | 
			
		||||
        self.b = backups.BackupsManager(self.mock_client)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_create(self, mock_requests):
 | 
			
		||||
        self.assertEqual('http://testendpoint:9999/v1/backups/', self.b.endpoint)
 | 
			
		||||
        self.assertEqual({'X-Auth-Token': 'testtoken'}, self.b.headers)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_create_ok(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 201
 | 
			
		||||
        mock_response.json.return_value = {'backup_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.post.return_value = mock_response
 | 
			
		||||
        retval = self.b.create(backup_metadata={'backup': 'metadata'})
 | 
			
		||||
        self.assertEqual('qwerqwer', retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_create_fail_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 500
 | 
			
		||||
        mock_requests.post.return_value = mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.b.create, {'backup': 'metadata'})
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_delete_ok(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 204
 | 
			
		||||
        mock_requests.delete.return_value = mock_response
 | 
			
		||||
        retval = self.b.delete('test_backup_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_delete_fail(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 500
 | 
			
		||||
        mock_requests.delete.return_value = mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.b.delete, 'test_backup_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_get_ok(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 200
 | 
			
		||||
        mock_response.json.return_value = {'backup_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        retval = self.b.get('test_backup_id')
 | 
			
		||||
        self.assertEqual({'backup_id': 'qwerqwer'}, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_get_none(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 404
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        retval = self.b.get('test_backup_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_get_error(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 403
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException,
 | 
			
		||||
                          self.b.get, 'test_backup_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_list_ok(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 200
 | 
			
		||||
        backup_list = [{'backup_id_0': 'qwerqwer'}, {'backup_id_1': 'asdfasdf'}]
 | 
			
		||||
        mock_response.json.return_value = {'backups': backup_list}
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        retval = self.b.list()
 | 
			
		||||
        self.assertEqual(backup_list, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_list_parameters(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 200
 | 
			
		||||
        backup_list = [{'backup_id_0': 'qwerqwer'}, {'backup_id_1': 'asdfasdf'}]
 | 
			
		||||
        mock_response.json.return_value = {'backups': backup_list}
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        retval = self.b.list(limit=5,
 | 
			
		||||
                             offset=5,
 | 
			
		||||
                             search={"time_before": 1428529956})
 | 
			
		||||
        mock_requests.get.assert_called_with(
 | 
			
		||||
            'http://testendpoint:9999/v1/backups/',
 | 
			
		||||
            params={'limit': 5, 'offset': 5},
 | 
			
		||||
            data='{"time_before": 1428529956}',
 | 
			
		||||
            headers={'X-Auth-Token': 'testtoken'},
 | 
			
		||||
            verify=True)
 | 
			
		||||
        self.assertEqual(backup_list, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.backups.requests')
 | 
			
		||||
    def test_list_error(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 404
 | 
			
		||||
        backup_list = [{'backup_id_0': 'qwerqwer'}, {'backup_id_1': 'asdfasdf'}]
 | 
			
		||||
        mock_response.json.return_value = {'backups': backup_list}
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.b.list)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										109
									
								
								freezerclient/tests/unit/v1/test_client_clients.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								freezerclient/tests/unit/v1/test_client_clients.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
# (c) Copyright 2014,2015,2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
from freezerclient.v1.client import clients
 | 
			
		||||
 | 
			
		||||
from mock import Mock, patch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestClientManager(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.mock_client = Mock()
 | 
			
		||||
        self.mock_client.endpoint = 'http://testendpoint:9999'
 | 
			
		||||
        self.mock_client.auth_token = 'testtoken'
 | 
			
		||||
        self.r = clients.ClientManager(self.mock_client)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_create(self, mock_requests):
 | 
			
		||||
        self.assertEqual('http://testendpoint:9999/v1/clients/', self.r.endpoint)
 | 
			
		||||
        self.assertEqual({'X-Auth-Token': 'testtoken'}, self.r.headers)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_create_ok(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 201
 | 
			
		||||
        mock_response.json.return_value = {'client_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.post.return_value = mock_response
 | 
			
		||||
        retval = self.r.create(client_info={'client': 'metadata'})
 | 
			
		||||
        self.assertEqual('qwerqwer', retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_create_fail_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 500
 | 
			
		||||
        mock_requests.post.return_value = mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.r.create, {'client': 'metadata'})
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_delete_ok(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 204
 | 
			
		||||
        mock_requests.delete.return_value = mock_response
 | 
			
		||||
        retval = self.r.delete('test_client_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_delete_fail(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 500
 | 
			
		||||
        mock_requests.delete.return_value = mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.r.delete, 'test_client_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_get_ok(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 200
 | 
			
		||||
        mock_response.json.return_value = {'client_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        retval = self.r.get('test_client_id')
 | 
			
		||||
        self.assertEqual({'client_id': 'qwerqwer'}, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_get_none(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 404
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        retval = self.r.get('test_client_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_get_raises_ApiClientException_on_error_not_404(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 500
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.r.get, 'test_client_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_list_ok(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 200
 | 
			
		||||
        client_list = [{'client_id_0': 'qwerqwer'}, {'client_id_1': 'asdfasdf'}]
 | 
			
		||||
        mock_response.json.return_value = {'clients': client_list}
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        retval = self.r.list()
 | 
			
		||||
        self.assertEqual(client_list, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.clients.requests')
 | 
			
		||||
    def test_list_error(self, mock_requests):
 | 
			
		||||
        mock_response = Mock()
 | 
			
		||||
        mock_response.status_code = 404
 | 
			
		||||
        client_list = [{'client_id_0': 'qwerqwer'}, {'client_id_1': 'asdfasdf'}]
 | 
			
		||||
        mock_response.json.return_value = {'clients': client_list}
 | 
			
		||||
        mock_requests.get.return_value = mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.r.list)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										239
									
								
								freezerclient/tests/unit/v1/test_client_jobs.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								freezerclient/tests/unit/v1/test_client_jobs.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
			
		||||
# (c) Copyright 2014,2015,2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
from freezerclient.v1.client import jobs
 | 
			
		||||
 | 
			
		||||
from mock import Mock, patch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestJobManager(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.mock_client = Mock()
 | 
			
		||||
        self.mock_response = Mock()
 | 
			
		||||
        self.mock_client.endpoint = 'http://testendpoint:9999'
 | 
			
		||||
        self.mock_client.auth_token = 'testtoken'
 | 
			
		||||
        self.headers = {'X-Auth-Token': 'testtoken'}
 | 
			
		||||
        self.mock_client.client_id = 'test_client_id_78900987'
 | 
			
		||||
        self.job_manager = jobs.JobManager(self.mock_client)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_create(self, mock_requests):
 | 
			
		||||
        self.assertEqual('http://testendpoint:9999/v1/jobs/', self.job_manager.endpoint)
 | 
			
		||||
        self.assertEqual({'X-Auth-Token': 'testtoken'}, self.job_manager.headers)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_create_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 201
 | 
			
		||||
        self.mock_response.json.return_value = {'job_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        retval = self.job_manager.create({'job': 'metadata'})
 | 
			
		||||
        self.assertEqual('qwerqwer', retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.json')
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_create_adds_client_id_if_not_provided(self, mock_requests, mock_json):
 | 
			
		||||
        self.mock_response.status_code = 201
 | 
			
		||||
        self.mock_response.json.return_value = {'job_id': 'qwerqwer'}
 | 
			
		||||
        mock_json.dumps.return_value = {'job': 'mocked'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
 | 
			
		||||
        retval = self.job_manager.create({'job': 'metadata'})
 | 
			
		||||
 | 
			
		||||
        mock_json.dumps.assert_called_with({'job': 'metadata',
 | 
			
		||||
                                            'client_id': 'test_client_id_78900987'})
 | 
			
		||||
        self.assertEqual('qwerqwer', retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.json')
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_create_leaves_provided_client_id(self, mock_requests, mock_json):
 | 
			
		||||
        self.mock_response.status_code = 201
 | 
			
		||||
        self.mock_response.json.return_value = {'job_id': 'qwerqwer'}
 | 
			
		||||
        mock_json.dumps.return_value = {'job': 'mocked'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
 | 
			
		||||
        retval = self.job_manager.create({'job': 'metadata', 'client_id': 'parmenide'})
 | 
			
		||||
 | 
			
		||||
        mock_json.dumps.assert_called_with({'job': 'metadata',
 | 
			
		||||
                                            'client_id': 'parmenide'})
 | 
			
		||||
        self.assertEqual('qwerqwer', retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_create_fail_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.job_manager.create, {'job': 'metadata'})
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_delete_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 204
 | 
			
		||||
        mock_requests.delete.return_value = self.mock_response
 | 
			
		||||
        retval = self.job_manager.delete('test_job_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_delete_fail(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.delete.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.job_manager.delete, 'test_job_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_get_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 200
 | 
			
		||||
        self.mock_response.json.return_value = {'job_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        retval = self.job_manager.get('test_job_id')
 | 
			
		||||
        self.assertEqual({'job_id': 'qwerqwer'}, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_get_fails_on_error_different_from_404(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.job_manager.get, 'test_job_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_get_none(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 404
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        retval = self.job_manager.get('test_job_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_list_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 200
 | 
			
		||||
        job_list = [{'job_id_0': 'bomboloid'}, {'job_id_1': 'asdfasdf'}]
 | 
			
		||||
        self.mock_response.json.return_value = {'jobs': job_list}
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        retval = self.job_manager.list()
 | 
			
		||||
        self.assertEqual(job_list, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_list_error(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 404
 | 
			
		||||
        job_list = [{'job_id_0': 'bomboloid'}, {'job_id_1': 'asdfasdf'}]
 | 
			
		||||
        self.mock_response.json.return_value = {'clients': job_list}
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.job_manager.list)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_update_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 200
 | 
			
		||||
        self.mock_response.json.return_value = {
 | 
			
		||||
            "patch": {"status": "bamboozled"},
 | 
			
		||||
            "version": 12,
 | 
			
		||||
            "job_id": "d454beec-1f3c-4d11-aa1a-404116a40502"
 | 
			
		||||
        }
 | 
			
		||||
        mock_requests.patch.return_value = self.mock_response
 | 
			
		||||
        retval = self.job_manager.update('d454beec-1f3c-4d11-aa1a-404116a40502', {'status': 'bamboozled'})
 | 
			
		||||
        self.assertEqual(12, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_update_raise_MetadataUpdateFailure_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        self.mock_response.json.return_value = {
 | 
			
		||||
            "patch": {"status": "bamboozled"},
 | 
			
		||||
            "version": 12,
 | 
			
		||||
            "job_id": "d454beec-1f3c-4d11-aa1a-404116a40502"
 | 
			
		||||
        }
 | 
			
		||||
        self.mock_response.status_code = 404
 | 
			
		||||
        self.mock_response.text = '{"title": "Not Found","description":"No document found with ID d454beec-1f3c-4d11-aa1a-404116a40502x"}'
 | 
			
		||||
        mock_requests.patch.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.job_manager.update,
 | 
			
		||||
                          'd454beec-1f3c-4d11-aa1a-404116a40502', {'status': 'bamboozled'})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_start_job_posts_proper_data(self, mock_requests):
 | 
			
		||||
        job_id = 'jobdfsfnqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 202
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        # /v1/jobs/{job_id}/event
 | 
			
		||||
 | 
			
		||||
        endpoint = '{0}/v1/jobs/{1}/event'.format(self.mock_client.endpoint, job_id)
 | 
			
		||||
        data = {"start": None}
 | 
			
		||||
        retval = self.job_manager.start_job(job_id)
 | 
			
		||||
        self.assertEqual({'result': 'success'}, retval)
 | 
			
		||||
 | 
			
		||||
        args = mock_requests.post.call_args[0]
 | 
			
		||||
        kwargs = mock_requests.post.call_args[1]
 | 
			
		||||
        self.assertEquals(endpoint, args[0])
 | 
			
		||||
        self.assertEquals(data, json.loads(kwargs['data']))
 | 
			
		||||
        self.assertEquals(self.headers, kwargs['headers'])
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_start_job_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        job_id = 'jobdfsfnqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.job_manager.start_job, job_id)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_stop_job_posts_proper_data(self, mock_requests):
 | 
			
		||||
        job_id = 'jobdfsfnqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 202
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        # /v1/jobs/{job_id}/event
 | 
			
		||||
 | 
			
		||||
        endpoint = '{0}/v1/jobs/{1}/event'.format(self.mock_client.endpoint, job_id)
 | 
			
		||||
        data = {"stop": None}
 | 
			
		||||
        retval = self.job_manager.stop_job(job_id)
 | 
			
		||||
        self.assertEqual({'result': 'success'}, retval)
 | 
			
		||||
 | 
			
		||||
        args = mock_requests.post.call_args[0]
 | 
			
		||||
        kwargs = mock_requests.post.call_args[1]
 | 
			
		||||
        self.assertEquals(endpoint, args[0])
 | 
			
		||||
        self.assertEquals(data, json.loads(kwargs['data']))
 | 
			
		||||
        self.assertEquals(self.headers, kwargs['headers'])
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_stop_job_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        job_id = 'jobdfsfnqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.job_manager.start_job, job_id)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_abort_job_posts_proper_data(self, mock_requests):
 | 
			
		||||
        job_id = 'jobdfsfnqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 202
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        # /v1/jobs/{job_id}/event
 | 
			
		||||
 | 
			
		||||
        endpoint = '{0}/v1/jobs/{1}/event'.format(self.mock_client.endpoint, job_id)
 | 
			
		||||
        data = {"abort": None}
 | 
			
		||||
        retval = self.job_manager.abort_job(job_id)
 | 
			
		||||
        self.assertEqual({'result': 'success'}, retval)
 | 
			
		||||
 | 
			
		||||
        args = mock_requests.post.call_args[0]
 | 
			
		||||
        kwargs = mock_requests.post.call_args[1]
 | 
			
		||||
        self.assertEquals(endpoint, args[0])
 | 
			
		||||
        self.assertEquals(data, json.loads(kwargs['data']))
 | 
			
		||||
        self.assertEquals(self.headers, kwargs['headers'])
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.jobs.requests')
 | 
			
		||||
    def test_abort_job_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        job_id = 'jobdfsfnqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.job_manager.abort_job, job_id)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										222
									
								
								freezerclient/tests/unit/v1/test_client_sessions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								freezerclient/tests/unit/v1/test_client_sessions.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,222 @@
 | 
			
		||||
# (c) Copyright 2014,2015,2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
from freezerclient.v1.client import sessions
 | 
			
		||||
 | 
			
		||||
from mock import Mock, patch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestSessionManager(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.mock_client = Mock()
 | 
			
		||||
        self.mock_response = Mock()
 | 
			
		||||
        self.mock_client.endpoint = 'http://testendpoint:9999'
 | 
			
		||||
        self.mock_client.auth_token = 'testtoken'
 | 
			
		||||
        self.mock_client.client_id = 'test_client_id_78900987'
 | 
			
		||||
        self.session_manager = sessions.SessionManager(self.mock_client)
 | 
			
		||||
        self.endpoint = 'http://testendpoint:9999/v1/sessions/'
 | 
			
		||||
        self.headers = {'X-Auth-Token': 'testtoken'}
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_create(self, mock_requests):
 | 
			
		||||
        self.assertEqual(self.endpoint, self.session_manager.endpoint)
 | 
			
		||||
        self.assertEqual(self.headers, self.session_manager.headers)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_create_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 201
 | 
			
		||||
        self.mock_response.json.return_value = {'session_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        retval = self.session_manager.create({'session': 'metadata'})
 | 
			
		||||
        self.assertEqual('qwerqwer', retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_create_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.session_manager.create, {'session': 'metadata'})
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_delete_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 204
 | 
			
		||||
        mock_requests.delete.return_value = self.mock_response
 | 
			
		||||
        retval = self.session_manager.delete('test_session_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_delete_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.delete.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.session_manager.delete, 'test_session_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_get_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 200
 | 
			
		||||
        self.mock_response.json.return_value = {'session_id': 'qwerqwer'}
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        retval = self.session_manager.get('test_session_id')
 | 
			
		||||
        self.assertEqual({'session_id': 'qwerqwer'}, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_get_raise_ApiClientException_when_api_return_error_different_from_404(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.session_manager.get, 'test_session_id')
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_get_none(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 404
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        retval = self.session_manager.get('test_session_id')
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_list_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 200
 | 
			
		||||
        session_list = [{'session_id_0': 'bomboloid'}, {'session_id_1': 'asdfasdf'}]
 | 
			
		||||
        self.mock_response.json.return_value = {'sessions': session_list}
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        retval = self.session_manager.list()
 | 
			
		||||
        self.assertEqual(session_list, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_list_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 404
 | 
			
		||||
        session_list = [{'session_id_0': 'bomboloid'}, {'session_id_1': 'asdfasdf'}]
 | 
			
		||||
        self.mock_response.json.return_value = {'clients': session_list}
 | 
			
		||||
        mock_requests.get.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.session_manager.list)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_update_ok(self, mock_requests):
 | 
			
		||||
        self.mock_response.status_code = 200
 | 
			
		||||
        self.mock_response.json.return_value = {
 | 
			
		||||
            "patch": {"status": "bamboozled"},
 | 
			
		||||
            "version": 12,
 | 
			
		||||
            "session_id": "d454beec-1f3c-4d11-aa1a-404116a40502"
 | 
			
		||||
        }
 | 
			
		||||
        mock_requests.patch.return_value = self.mock_response
 | 
			
		||||
        retval = self.session_manager.update('d454beec-1f3c-4d11-aa1a-404116a40502', {'status': 'bamboozled'})
 | 
			
		||||
        self.assertEqual(12, retval)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_update_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        self.mock_response.json.return_value = {
 | 
			
		||||
            "patch": {"status": "bamboozled"},
 | 
			
		||||
            "version": 12,
 | 
			
		||||
            "session_id": "d454beec-1f3c-4d11-aa1a-404116a40502"
 | 
			
		||||
        }
 | 
			
		||||
        self.mock_response.status_code = 404
 | 
			
		||||
        self.mock_response.text = '{"title": "Not Found","description":"No document found with ID d454beec-1f3c-4d11-aa1a-404116a40502x"}'
 | 
			
		||||
        mock_requests.patch.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.session_manager.update,
 | 
			
		||||
                          'd454beec-1f3c-4d11-aa1a-404116a40502', {'status': 'bamboozled'})
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_add_job_uses_proper_endpoint(self, mock_requests):
 | 
			
		||||
        session_id, job_id = 'sessionqwerty1234', 'jobqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 204
 | 
			
		||||
        mock_requests.put.return_value = self.mock_response
 | 
			
		||||
        endpoint = '{0}{1}/jobs/{2}'.format(self.endpoint, session_id, job_id)
 | 
			
		||||
 | 
			
		||||
        retval = self.session_manager.add_job(session_id, job_id)
 | 
			
		||||
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
        mock_requests.put.assert_called_with(endpoint, headers=self.headers, verify=True)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_add_job_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        session_id, job_id = 'sessionqwerty1234', 'jobqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.put.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.session_manager.add_job, session_id, job_id)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_remove_job_uses_proper_endpoint(self, mock_requests):
 | 
			
		||||
        session_id, job_id = 'sessionqwerty1234', 'jobqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 204
 | 
			
		||||
        mock_requests.delete.return_value = self.mock_response
 | 
			
		||||
        endpoint = '{0}{1}/jobs/{2}'.format(self.endpoint, session_id, job_id)
 | 
			
		||||
 | 
			
		||||
        retval = self.session_manager.remove_job(session_id, job_id)
 | 
			
		||||
 | 
			
		||||
        self.assertIsNone(retval)
 | 
			
		||||
        mock_requests.delete.assert_called_with(endpoint, headers=self.headers, verify=True)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_remove_job_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        session_id, job_id = 'sessionqwerty1234', 'jobqwerty1234'
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        mock_requests.delete.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.session_manager.remove_job, session_id, job_id)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_start_session_posts_proper_data(self, mock_requests):
 | 
			
		||||
        session_id, job_id, tag = 'sessionqwerty1234', 'jobqwerty1234', 23
 | 
			
		||||
        self.mock_response.status_code = 202
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success', 'session_tag': 24}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        # /v1/sessions/{sessions_id}/action
 | 
			
		||||
        endpoint = '{0}{1}/action'.format(self.endpoint, session_id)
 | 
			
		||||
        data = {"start": {"current_tag": 23, "job_id": "jobqwerty1234"}}
 | 
			
		||||
        retval = self.session_manager.start_session(session_id, job_id, tag)
 | 
			
		||||
        self.assertEqual({'result': 'success', 'session_tag': 24}, retval)
 | 
			
		||||
 | 
			
		||||
        args = mock_requests.post.call_args[0]
 | 
			
		||||
        kwargs = mock_requests.post.call_args[1]
 | 
			
		||||
        self.assertEquals(endpoint, args[0])
 | 
			
		||||
        self.assertEquals(data, json.loads(kwargs['data']))
 | 
			
		||||
        self.assertEquals(self.headers, kwargs['headers'])
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_start_session_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        session_id, job_id, tag = 'sessionqwerty1234', 'jobqwerty1234', 23
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success', 'session_tag': 24}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.session_manager.start_session,
 | 
			
		||||
                          session_id, job_id, tag)
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_end_session_posts_proper_data(self, mock_requests):
 | 
			
		||||
        session_id, job_id, tag = 'sessionqwerty1234', 'jobqwerty1234', 23
 | 
			
		||||
        self.mock_response.status_code = 202
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success', 'session_tag': 24}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        # /v1/sessions/{sessions_id}/action
 | 
			
		||||
        endpoint = '{0}{1}/action'.format(self.endpoint, session_id)
 | 
			
		||||
        data = {"end": {"current_tag": 23, "job_id": "jobqwerty1234", "result": "fail"}}
 | 
			
		||||
        retval = self.session_manager.end_session(session_id, job_id, tag, 'fail')
 | 
			
		||||
        self.assertEqual({'result': 'success', 'session_tag': 24}, retval)
 | 
			
		||||
 | 
			
		||||
        args = mock_requests.post.call_args[0]
 | 
			
		||||
        kwargs = mock_requests.post.call_args[1]
 | 
			
		||||
        self.assertEquals(endpoint, args[0])
 | 
			
		||||
        self.assertEquals(data, json.loads(kwargs['data']))
 | 
			
		||||
        self.assertEquals(self.headers, kwargs['headers'])
 | 
			
		||||
 | 
			
		||||
    @patch('freezerclient.v1.managers.sessions.requests')
 | 
			
		||||
    def test_end_session_raise_ApiClientException_when_api_return_error_code(self, mock_requests):
 | 
			
		||||
        session_id, job_id, tag = 'sessionqwerty1234', 'jobqwerty1234', 23
 | 
			
		||||
        self.mock_response.status_code = 500
 | 
			
		||||
        self.mock_response.json.return_value = {'result': 'success', 'session_tag': 24}
 | 
			
		||||
        mock_requests.post.return_value = self.mock_response
 | 
			
		||||
        self.assertRaises(exceptions.ApiClientException, self.session_manager.end_session,
 | 
			
		||||
                          session_id, job_id, tag, 'fail')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										119
									
								
								freezerclient/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								freezerclient/utils.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
logging = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Namespace(dict):
 | 
			
		||||
    """A dict subclass that exposes its items as attributes.
 | 
			
		||||
 | 
			
		||||
    Warning: Namespace instances do not have direct access to the
 | 
			
		||||
    dict methods.
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, obj={}):
 | 
			
		||||
        super(Namespace, self).__init__(obj)
 | 
			
		||||
 | 
			
		||||
    def __dir__(self):
 | 
			
		||||
        return tuple(self)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return "%s(%s)" % (type(self).__name__,
 | 
			
		||||
                           super(Namespace, self).__repr__())
 | 
			
		||||
 | 
			
		||||
    def __getattribute__(self, name):
 | 
			
		||||
        try:
 | 
			
		||||
            return self[name]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            # Return None in case the value doesn't exists
 | 
			
		||||
            # this is not an issue for the apiclient because it skips
 | 
			
		||||
            # None values
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
    def __setattr__(self, name, value):
 | 
			
		||||
        self[name] = value
 | 
			
		||||
 | 
			
		||||
    def __delattr__(self, name):
 | 
			
		||||
        del self[name]
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_object(cls, obj, names=None):
 | 
			
		||||
        if names is None:
 | 
			
		||||
            names = dir(obj)
 | 
			
		||||
        ns = {name:getattr(obj, name) for name in names}
 | 
			
		||||
        return cls(ns)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_mapping(cls, ns, names=None):
 | 
			
		||||
        if names:
 | 
			
		||||
            ns = {name: ns[name] for name in names}
 | 
			
		||||
        return cls(ns)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_sequence(cls, seq, names=None):
 | 
			
		||||
        if names:
 | 
			
		||||
            seq = {name: val for name, val in seq if name in names}
 | 
			
		||||
        return cls(seq)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def hasattr(ns, name):
 | 
			
		||||
        try:
 | 
			
		||||
            object.__getattribute__(ns, name)
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
            return False
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def getattr(ns, name):
 | 
			
		||||
        return object.__getattribute__(ns, name)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def setattr(ns, name, value):
 | 
			
		||||
        return object.__setattr__(ns, name, value)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def delattr(ns, name):
 | 
			
		||||
        return object.__delattr__(ns, name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CachedProperty(object):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, func):
 | 
			
		||||
        self.__doc__ = getattr(func, '__doc__')
 | 
			
		||||
        self.func = func
 | 
			
		||||
 | 
			
		||||
    def __get__(self, obj, cls):
 | 
			
		||||
        if obj is None:
 | 
			
		||||
            return self
 | 
			
		||||
        value = obj.__dict__[self.func.__name__] = self.func(obj)
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def doc_from_json_file(path_to_file):
 | 
			
		||||
    """Build a json from a file in the file system
 | 
			
		||||
    :param path_to_file: path to file
 | 
			
		||||
    :return: in memory file in json format
 | 
			
		||||
    """
 | 
			
		||||
    with open(path_to_file, 'rb') as fd:
 | 
			
		||||
        try:
 | 
			
		||||
            return json.load(fd)
 | 
			
		||||
        except Exception as err:
 | 
			
		||||
            logging.error(err)
 | 
			
		||||
            raise Exception('Unable to load conf file. {0}'.format(err))
 | 
			
		||||
							
								
								
									
										0
									
								
								freezerclient/v1/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								freezerclient/v1/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										153
									
								
								freezerclient/v1/actions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								freezerclient/v1/actions.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from cliff.command import Command
 | 
			
		||||
from cliff.lister import Lister
 | 
			
		||||
from cliff.show import ShowOne
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
from freezerclient.utils import doc_from_json_file
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
logging = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActionShow(ShowOne):
 | 
			
		||||
    """Show a single action """
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ActionShow, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='action_id',
 | 
			
		||||
                            help='ID of the action')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        action = self.app.client.actions.get(parsed_args.action_id)
 | 
			
		||||
 | 
			
		||||
        if not action:
 | 
			
		||||
            raise exceptions.ApiClientException('Action not found')
 | 
			
		||||
 | 
			
		||||
        column = (
 | 
			
		||||
            'Action ID',
 | 
			
		||||
            'Name',
 | 
			
		||||
            'Action',
 | 
			
		||||
            'Mode',
 | 
			
		||||
            'Path to Backup or Restore',
 | 
			
		||||
            'Storage',
 | 
			
		||||
            'Snapshot'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        data = (
 | 
			
		||||
            action.get('action_id'),
 | 
			
		||||
            action.get('freezer_action', {}).get('backup_name', ''),
 | 
			
		||||
            action.get('freezer_action', {}).get('action', 'backup'),
 | 
			
		||||
            action.get('freezer_action', {}).get('mode', 'fs'),
 | 
			
		||||
            action.get('freezer_action', {}).get('path_to_backup', ''),
 | 
			
		||||
            action.get('freezer_action', {}).get('storage', 'swift'),
 | 
			
		||||
            action.get('freezer_action', {}).get('snapshot', 'False'),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return column, data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActionList(Lister):
 | 
			
		||||
    """List all actions for your user"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ActionList, self).get_parser(prog_name)
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--limit',
 | 
			
		||||
            dest='limit',
 | 
			
		||||
            default=100,
 | 
			
		||||
            help='Specify a limit for search query',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--offset',
 | 
			
		||||
            dest='offset',
 | 
			
		||||
            default=0,
 | 
			
		||||
            help='',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--search',
 | 
			
		||||
            dest='search',
 | 
			
		||||
            default='',
 | 
			
		||||
            help='Define a filter for the query',
 | 
			
		||||
        )
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        actions = self.app.client.actions.list(
 | 
			
		||||
            limit=parsed_args.limit,
 | 
			
		||||
            offset=parsed_args.offset,
 | 
			
		||||
            search=parsed_args.search
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return (('Action ID', 'Name', 'Action',
 | 
			
		||||
                 'Path to Backup or Restore', 'Mode', 'Storage', 'snapshot'),
 | 
			
		||||
                ((action.get('action_id'),
 | 
			
		||||
                  action.get('freezer_action', {}).get('backup_name', ''),
 | 
			
		||||
                  action.get('freezer_action', {}).get('action', 'backup'),
 | 
			
		||||
                  action.get('freezer_action', {}).get('path_to_backup', ''),
 | 
			
		||||
                  action.get('freezer_action', {}).get('mode', 'fs'),
 | 
			
		||||
                  action.get('freezer_action', {}).get('storage', 'swift'),
 | 
			
		||||
                  action.get('freezer_action', {}).get('snapshot', 'False')
 | 
			
		||||
                  ) for action in actions))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActionDelete(Command):
 | 
			
		||||
    """Delete an action from the api"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ActionDelete, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='action_id',
 | 
			
		||||
                            help='ID of the action')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        self.app.client.actions.delete(parsed_args.action_id)
 | 
			
		||||
        logging.info('Action {0} deleted'.format(parsed_args.action_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActionCreate(Command):
 | 
			
		||||
    """Create an action from a file"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ActionCreate, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument('--file',
 | 
			
		||||
                            dest='file',
 | 
			
		||||
                            help='Path to json file with the action')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        action = doc_from_json_file(parsed_args.file)
 | 
			
		||||
        action_id = self.app.client.actions.create(action)
 | 
			
		||||
        logging.info('Action {0} created'.format(action_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActionUpdate(Command):
 | 
			
		||||
    """Update an action from a file"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ActionUpdate, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='action_id',
 | 
			
		||||
                            help='ID of the session')
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(dest='file',
 | 
			
		||||
                            help='Path to json file with the action')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        action = doc_from_json_file(parsed_args.file)
 | 
			
		||||
        self.app.client.actions.update(parsed_args.action_id, action)
 | 
			
		||||
        logging.info('Action {0} updated'.format(parsed_args.action_id))
 | 
			
		||||
							
								
								
									
										98
									
								
								freezerclient/v1/backups.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								freezerclient/v1/backups.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from pprint import pformat
 | 
			
		||||
 | 
			
		||||
from cliff.lister import Lister
 | 
			
		||||
from cliff.show import ShowOne
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
logging = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BackupShow(ShowOne):
 | 
			
		||||
    """Show the metadata of a single backup"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(BackupShow, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='backup_uuid',
 | 
			
		||||
                            help='UUID of the backup')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        # due to the fact that a backup_id is composed of several strings
 | 
			
		||||
        # some of them may include a slash "/" so it will never find the correct
 | 
			
		||||
        # backup, so the workaround for this version is to use the backup_uuid as
 | 
			
		||||
        # a filter for the search. this won't work when the user wants to delete a
 | 
			
		||||
        # backup, but that functionality is yet to be provided by the api.
 | 
			
		||||
        search = {"match": [{"backup_uuid": parsed_args.backup_uuid}, ], }
 | 
			
		||||
        backup = self.app.client.backups.list(search=search)
 | 
			
		||||
 | 
			
		||||
        if not backup:
 | 
			
		||||
            raise exceptions.ApiClientException('Backup not found')
 | 
			
		||||
 | 
			
		||||
        backup = backup[0]
 | 
			
		||||
 | 
			
		||||
        column = (
 | 
			
		||||
            'Backup ID',
 | 
			
		||||
            'Backup UUID',
 | 
			
		||||
            'Metadata'
 | 
			
		||||
        )
 | 
			
		||||
        data = (
 | 
			
		||||
            backup.get('backup_id'),
 | 
			
		||||
            backup.get('backup_uuid'),
 | 
			
		||||
            pformat(backup.get('backup_metadata'))
 | 
			
		||||
        )
 | 
			
		||||
        return column, data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BackupList(Lister):
 | 
			
		||||
    """List all backups for your user"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(BackupList, self).get_parser(prog_name)
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--limit',
 | 
			
		||||
            dest='limit',
 | 
			
		||||
            default=100,
 | 
			
		||||
            help='Specify a limit for search query',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--offset',
 | 
			
		||||
            dest='offset',
 | 
			
		||||
            default=0,
 | 
			
		||||
            help='',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--search',
 | 
			
		||||
            dest='search',
 | 
			
		||||
            default='',
 | 
			
		||||
            help='Define a filter for the query',
 | 
			
		||||
        )
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        backups = self.app.client.backups.list(limit=parsed_args.limit,
 | 
			
		||||
                                               offset=parsed_args.offset,
 | 
			
		||||
                                               search=parsed_args.search)
 | 
			
		||||
        return (('Backup ID', 'Backup UUID'),
 | 
			
		||||
                ((backup.get('backup_id'),
 | 
			
		||||
                  backup.get('backup_uuid'),
 | 
			
		||||
                  ) for backup in backups))
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										147
									
								
								freezerclient/v1/client.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								freezerclient/v1/client.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import socket
 | 
			
		||||
 | 
			
		||||
from freezerclient.utils import CachedProperty
 | 
			
		||||
from freezerclient.utils import Namespace
 | 
			
		||||
from freezerclient.v1.managers import actions
 | 
			
		||||
from freezerclient.v1.managers import backups
 | 
			
		||||
from freezerclient.v1.managers import clients
 | 
			
		||||
from freezerclient.v1.managers import jobs
 | 
			
		||||
from freezerclient.v1.managers import sessions
 | 
			
		||||
 | 
			
		||||
from keystoneclient.auth.identity import v2
 | 
			
		||||
from keystoneclient.auth.identity import v3
 | 
			
		||||
from keystoneclient import session as ksc_session
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def guess_auth_version(opts):
 | 
			
		||||
    """ Guess keystone version to connect to"""
 | 
			
		||||
    if opts.os_identity_api_version == '3':
 | 
			
		||||
        return '3'
 | 
			
		||||
    elif opts.os_identity_api_version == '2.0':
 | 
			
		||||
        return '2.0'
 | 
			
		||||
    elif opts.os_auth_url.endswith('v3'):
 | 
			
		||||
        return '3'
 | 
			
		||||
    elif opts.os_auth_url.endswith('v2.0'):
 | 
			
		||||
        return '2.0'
 | 
			
		||||
    raise Exception('Please provide valid keystone auth url with valid'
 | 
			
		||||
                    ' keystone api version to use')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_auth_plugin(opts):
 | 
			
		||||
    """Create the right keystone connection depending on the version
 | 
			
		||||
    for the api, if username/password and token are provided, username and
 | 
			
		||||
    password takes precedence.
 | 
			
		||||
    """
 | 
			
		||||
    auth_version = guess_auth_version(opts)
 | 
			
		||||
    if opts.os_username:
 | 
			
		||||
        if auth_version == '3':
 | 
			
		||||
            return v3.Password(auth_url=opts.os_auth_url,
 | 
			
		||||
                               username=opts.os_username,
 | 
			
		||||
                               password=opts.os_password,
 | 
			
		||||
                               project_name=opts.os_project_name,
 | 
			
		||||
                               user_domain_name=opts.os_user_domain_name,
 | 
			
		||||
                               project_domain_name=opts.os_project_domain_name)
 | 
			
		||||
        elif auth_version == '2.0':
 | 
			
		||||
            return v2.Password(auth_url=opts.os_auth_url,
 | 
			
		||||
                               username=opts.os_username,
 | 
			
		||||
                               password=opts.os_password,
 | 
			
		||||
                               tenant_name=opts.os_tenant_name)
 | 
			
		||||
    elif opts.os_token:
 | 
			
		||||
        if auth_version == '3':
 | 
			
		||||
            return v3.Token(auth_url=opts.os_auth_url,
 | 
			
		||||
                            token=opts.os_token,
 | 
			
		||||
                            project_name=opts.os_project_name,
 | 
			
		||||
                            project_domain_name=opts.os_project_domain_name)
 | 
			
		||||
        elif auth_version == '2.0':
 | 
			
		||||
            return v2.Token(auth_url=opts.os_auth_url,
 | 
			
		||||
                            token=opts.os_token,
 | 
			
		||||
                            tenant_name=opts.os_tenant_name)
 | 
			
		||||
    raise Exception('Unable to determine correct auth method, please provide'
 | 
			
		||||
                    ' either username or token')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Client(object):
 | 
			
		||||
    """Client for the OpenStack Disaster Recovery v1 API.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, version='3', token=None, username=None, password=None,
 | 
			
		||||
                 tenant_name=None, auth_url=None, session=None, endpoint=None,
 | 
			
		||||
                 opts=None, project_name=None, user_domain_name=None,
 | 
			
		||||
                 project_domain_name=None, verify=True, cert=None):
 | 
			
		||||
        """
 | 
			
		||||
        Initialize a new client for the Disaster Recovery v1 API.
 | 
			
		||||
        :param version: keystone version to use
 | 
			
		||||
        :param token: keystone token
 | 
			
		||||
        :param username: openstack username
 | 
			
		||||
        :param password: openstack password
 | 
			
		||||
        :param tenant_name: tenant
 | 
			
		||||
        :param auth_url: keystone-api endpoint
 | 
			
		||||
        :param session: keystone.Session
 | 
			
		||||
        :param endpoint: freezer-api endpoint
 | 
			
		||||
        :param opts: a namespace to store all keystone data
 | 
			
		||||
        :param project_name: only for version 3
 | 
			
		||||
        :param user_domain_name: only for version 3
 | 
			
		||||
        :param project_domain_name: only for version 3
 | 
			
		||||
        :param verify: The verification arguments to pass to requests.
 | 
			
		||||
                       These are of the same form as requests expects,
 | 
			
		||||
                       so True or False to verify (or not) against system
 | 
			
		||||
                       certificates or a path to a bundle or CA certs to
 | 
			
		||||
                       check against or None for requests to
 | 
			
		||||
                       attempt to locate and use certificates. (optional,
 | 
			
		||||
                       defaults to True)
 | 
			
		||||
        :param cert: Path to cert
 | 
			
		||||
        :return: freezerclient.Client
 | 
			
		||||
        """
 | 
			
		||||
        self.opts = opts or Namespace({})
 | 
			
		||||
        self.opts.os_token = token or None
 | 
			
		||||
        self.opts.os_username = username or None
 | 
			
		||||
        self.opts.os_password = password or None
 | 
			
		||||
        self.opts.os_tenant_name = tenant_name or None
 | 
			
		||||
        self.opts.os_auth_url = auth_url or None
 | 
			
		||||
        self.opts.os_backup_url = endpoint or None
 | 
			
		||||
        self.opts.os_project_name = project_name or None
 | 
			
		||||
        self.opts.os_user_domain_name = user_domain_name or None
 | 
			
		||||
        self.opts.os_project_domain_name = project_domain_name or None
 | 
			
		||||
        self.opts.auth_version = version
 | 
			
		||||
        self.verify = verify
 | 
			
		||||
        self.cert = cert
 | 
			
		||||
        self._session = session
 | 
			
		||||
        self.endpoint = endpoint
 | 
			
		||||
 | 
			
		||||
        self.jobs = jobs.JobManager(self, verify=verify)
 | 
			
		||||
        self.clients = clients.ClientManager(self, verify=verify)
 | 
			
		||||
        self.backups = backups.BackupsManager(self, verify=verify)
 | 
			
		||||
        self.sessions = sessions.SessionManager(self, verify=verify)
 | 
			
		||||
        self.actions = actions.ActionManager(self, verify=verify)
 | 
			
		||||
 | 
			
		||||
    @CachedProperty
 | 
			
		||||
    def session(self):
 | 
			
		||||
        if self._session:
 | 
			
		||||
            return self._session
 | 
			
		||||
        auth_plugin = get_auth_plugin(self.opts)
 | 
			
		||||
        return ksc_session.Session(auth=auth_plugin,
 | 
			
		||||
                                   verify=self.verify,
 | 
			
		||||
                                   cert=self.cert)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def auth_token(self):
 | 
			
		||||
        return self.session.get_token()
 | 
			
		||||
 | 
			
		||||
    @CachedProperty
 | 
			
		||||
    def client_id(self):
 | 
			
		||||
        return '{0}_{1}'.format(self.session.get_project_id(),
 | 
			
		||||
                                socket.gethostname())
 | 
			
		||||
							
								
								
									
										127
									
								
								freezerclient/v1/clients.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								freezerclient/v1/clients.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from cliff.command import Command
 | 
			
		||||
from cliff.lister import Lister
 | 
			
		||||
from cliff.show import ShowOne
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
from freezerclient.utils import doc_from_json_file
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
logging = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClientShow(ShowOne):
 | 
			
		||||
    """Show a single client"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ClientShow, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='client_id',
 | 
			
		||||
                            help='ID of the client')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        client = self.app.client.clients.get(parsed_args.client_id)
 | 
			
		||||
 | 
			
		||||
        if not client:
 | 
			
		||||
            raise exceptions.ApiClientException('Client not found')
 | 
			
		||||
 | 
			
		||||
        column = (
 | 
			
		||||
            'Client ID',
 | 
			
		||||
            'Client UUID',
 | 
			
		||||
            'hostname',
 | 
			
		||||
            'description'
 | 
			
		||||
        )
 | 
			
		||||
        data = (
 | 
			
		||||
            client.get('client', {}).get('client_id'),
 | 
			
		||||
            client.get('uuid'),
 | 
			
		||||
            client.get('client', {}).get('hostname'),
 | 
			
		||||
            client.get('client', {}).get('description', '')
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return column, data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClientList(Lister):
 | 
			
		||||
    """List of clients registered in the api"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ClientList, self).get_parser(prog_name)
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--limit',
 | 
			
		||||
            dest='limit',
 | 
			
		||||
            default=100,
 | 
			
		||||
            help='Specify a limit for search query',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--offset',
 | 
			
		||||
            dest='offset',
 | 
			
		||||
            default=0,
 | 
			
		||||
            help='',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--search',
 | 
			
		||||
            dest='search',
 | 
			
		||||
            default='',
 | 
			
		||||
            help='Define a filter for the query',
 | 
			
		||||
        )
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        clients = self.app.client.clients.list(limit=parsed_args.limit,
 | 
			
		||||
                                               offset=parsed_args.offset,
 | 
			
		||||
                                               search=parsed_args.search)
 | 
			
		||||
 | 
			
		||||
        return (('Client ID', 'uuid', 'hostname', 'description'),
 | 
			
		||||
                ((client.get('client', {}).get('client_id'),
 | 
			
		||||
                  client.get('uuid'),
 | 
			
		||||
                  client.get('client', {}).get('hostname'),
 | 
			
		||||
                  client.get('client', {}).get('description', '')
 | 
			
		||||
                  ) for client in clients))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClientDelete(Command):
 | 
			
		||||
    """Delete a client from the api"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ClientDelete, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='client_id',
 | 
			
		||||
                            help='ID of the client')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        self.app.client.clients.delete(parsed_args.client_id)
 | 
			
		||||
        logging.info('Client {0} deleted'.format(parsed_args.client_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ClientRegister(Command):
 | 
			
		||||
    """Register a new client"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(ClientRegister, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument('--file',
 | 
			
		||||
                            dest='file',
 | 
			
		||||
                            help='Path to json file with the client')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        client = doc_from_json_file(parsed_args.file)
 | 
			
		||||
        try:
 | 
			
		||||
            client_id = self.app.client.clients.create(client)
 | 
			
		||||
        except Exception as err:
 | 
			
		||||
            raise exceptions.ApiClientException(err.message)
 | 
			
		||||
        else:
 | 
			
		||||
            logging.info("Client {0} registered".format(client_id))
 | 
			
		||||
							
								
								
									
										221
									
								
								freezerclient/v1/jobs.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								freezerclient/v1/jobs.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,221 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from pprint import pformat
 | 
			
		||||
from pprint import pprint
 | 
			
		||||
 | 
			
		||||
from cliff.command import Command
 | 
			
		||||
from cliff.lister import Lister
 | 
			
		||||
from cliff.show import ShowOne
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
from freezerclient.utils import doc_from_json_file
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
logging = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobShow(ShowOne):
 | 
			
		||||
    """Show a single job"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(JobShow, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='job_id',
 | 
			
		||||
                            help='ID of the job')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        job = self.app.client.jobs.get(parsed_args.job_id)
 | 
			
		||||
 | 
			
		||||
        if not job:
 | 
			
		||||
            raise exceptions.ApiClientException('Job not found')
 | 
			
		||||
 | 
			
		||||
        column = (
 | 
			
		||||
            'Job ID',
 | 
			
		||||
            'Client ID',
 | 
			
		||||
            'User ID',
 | 
			
		||||
            'Session ID',
 | 
			
		||||
            'Description',
 | 
			
		||||
            'Actions',
 | 
			
		||||
            'Start Date',
 | 
			
		||||
            'End Date',
 | 
			
		||||
            'Interval',
 | 
			
		||||
        )
 | 
			
		||||
        data = (
 | 
			
		||||
            job.get('job_id'),
 | 
			
		||||
            job.get('client_id'),
 | 
			
		||||
            job.get('user_id'),
 | 
			
		||||
            job.get('session_id', ''),
 | 
			
		||||
            job.get('description'),
 | 
			
		||||
            pformat(job.get('job_actions')),
 | 
			
		||||
            job.get('job_schedule', {}).get('schedule_start_date', ''),
 | 
			
		||||
            job.get('job_schedule', {}).get('schedule_interval', ''),
 | 
			
		||||
            job.get('job_schedule', {}).get('schedule_end_date', ''),
 | 
			
		||||
        )
 | 
			
		||||
        return column, data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobList(Lister):
 | 
			
		||||
    """List all the jobs for your user"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(JobList, self).get_parser(prog_name)
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--limit',
 | 
			
		||||
            dest='limit',
 | 
			
		||||
            default=100,
 | 
			
		||||
            help='Specify a limit for search query',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--offset',
 | 
			
		||||
            dest='offset',
 | 
			
		||||
            default=0,
 | 
			
		||||
            help='',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--search',
 | 
			
		||||
            dest='search',
 | 
			
		||||
            default='',
 | 
			
		||||
            help='Define a filter for the query',
 | 
			
		||||
        )
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        jobs = self.app.client.jobs.list_all(
 | 
			
		||||
                limit=parsed_args.limit,
 | 
			
		||||
                offset=parsed_args.offset,
 | 
			
		||||
                search=parsed_args.search
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return (('Job ID', 'Description', '# Actions', 'Result', 'Event', 'Session ID'),
 | 
			
		||||
                ((job.get('job_id'),
 | 
			
		||||
                  job.get('description'),
 | 
			
		||||
                  len(job.get('job_actions', [])),
 | 
			
		||||
                  job.get('job_schedule', {}).get('result', ''),
 | 
			
		||||
                  job.get('job_schedule', {}).get('event', ''),
 | 
			
		||||
                  job.get('session_id', '')
 | 
			
		||||
                  ) for job in jobs))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobGet(Command):
 | 
			
		||||
    """Download a job as a json file"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(JobGet, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='job_id',
 | 
			
		||||
                            help='ID of the job')
 | 
			
		||||
 | 
			
		||||
        parser.add_argument('--no-format',
 | 
			
		||||
                            dest='no_format',
 | 
			
		||||
                            default=False,
 | 
			
		||||
                            action='store_true',
 | 
			
		||||
                            help='Return a job in json without pretty print')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        job = self.app.client.jobs.get(parsed_args.job_id)
 | 
			
		||||
 | 
			
		||||
        if not job:
 | 
			
		||||
            raise exceptions.ApiClientException('Job not found')
 | 
			
		||||
 | 
			
		||||
        if parsed_args.no_format:
 | 
			
		||||
            print(job)
 | 
			
		||||
        else:
 | 
			
		||||
            pprint(job)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobDelete(Command):
 | 
			
		||||
    """Delete a job from the api"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(JobDelete, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='job_id',
 | 
			
		||||
                            help='ID of the job')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        self.app.client.jobs.delete(parsed_args.job_id)
 | 
			
		||||
        logging.info('Job {0} deleted'.format(parsed_args.job_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobCreate(Command):
 | 
			
		||||
    """Create a new job from a file"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(JobCreate, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument('--file',
 | 
			
		||||
                            dest='file',
 | 
			
		||||
                            help='Path to json file with the job')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        job = doc_from_json_file(parsed_args.file)
 | 
			
		||||
        job_id = self.app.client.jobs.create(job)
 | 
			
		||||
        logging.info('Job {0} created'.format(job_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobStart(Command):
 | 
			
		||||
    """Send a start signal for a job"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(JobStart, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='job_id',
 | 
			
		||||
                            help='ID of the job')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        self.app.client.jobs.start_job(parsed_args.job_id)
 | 
			
		||||
        logging.info('Job {0} has started'.format(parsed_args.job_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobStop(Command):
 | 
			
		||||
    """Send a stop signal for a job"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(JobStop, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='job_id',
 | 
			
		||||
                            help='ID of the job')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        self.app.client.jobs.stop_job(parsed_args.job_id)
 | 
			
		||||
        logging.info('Job {0} has stopped'.format(parsed_args.job_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobAbort(Command):
 | 
			
		||||
    """Abort a running job"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(JobAbort, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='job_id',
 | 
			
		||||
                            help='ID of the job')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        self.app.client.jobs.abort_job(parsed_args.job_id)
 | 
			
		||||
        logging.info('Job {0} has been aborted'.format(parsed_args.job_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobUpdate(Command):
 | 
			
		||||
    """Update a job from a file"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(JobUpdate, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='job_id',
 | 
			
		||||
                            help='ID of the job')
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(dest='file',
 | 
			
		||||
                            help='Path to json file with the job')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        job = doc_from_json_file(parsed_args.file)
 | 
			
		||||
        self.app.client.jobs.update(parsed_args.job_id, job)
 | 
			
		||||
        logging.info('Job {0} updated'.format(parsed_args.job_id))
 | 
			
		||||
							
								
								
									
										0
									
								
								freezerclient/v1/managers/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								freezerclient/v1/managers/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -1,24 +1,21 @@
 | 
			
		||||
"""
 | 
			
		||||
Copyright 2015 Hewlett-Packard
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
from freezer.apiclient import exceptions
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActionManager(object):
 | 
			
		||||
@@ -1,23 +1,21 @@
 | 
			
		||||
"""
 | 
			
		||||
(c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
"""
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
from freezer.apiclient import exceptions
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BackupsManager(object):
 | 
			
		||||
@@ -1,26 +1,24 @@
 | 
			
		||||
"""
 | 
			
		||||
(c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
"""
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
from freezer.apiclient import exceptions
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RegistrationManager(object):
 | 
			
		||||
class ClientManager(object):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, client, verify=True):
 | 
			
		||||
        self.client = client
 | 
			
		||||
@@ -1,23 +1,21 @@
 | 
			
		||||
"""
 | 
			
		||||
Copyright 2015 Hewlett-Packard
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
"""
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
from freezer.apiclient import exceptions
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class JobManager(object):
 | 
			
		||||
@@ -1,23 +1,21 @@
 | 
			
		||||
"""
 | 
			
		||||
Copyright 2015 Hewlett-Packard
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
"""
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
from freezer.apiclient import exceptions
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionManager(object):
 | 
			
		||||
@@ -138,7 +136,7 @@ class SessionManager(object):
 | 
			
		||||
    def end_session(self, session_id, job_id, session_tag, result):
 | 
			
		||||
        """
 | 
			
		||||
        Informs the freezer service that the job has ended.
 | 
			
		||||
        Privides information about the job's result and the session tag
 | 
			
		||||
        Provides information about the job's result and the session tag
 | 
			
		||||
 | 
			
		||||
        :param session_id:
 | 
			
		||||
        :param job_id:
 | 
			
		||||
							
								
								
									
										198
									
								
								freezerclient/v1/sessions.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								freezerclient/v1/sessions.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,198 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from pprint import pformat
 | 
			
		||||
 | 
			
		||||
from cliff.command import Command
 | 
			
		||||
from cliff.lister import Lister
 | 
			
		||||
from cliff.show import ShowOne
 | 
			
		||||
 | 
			
		||||
from freezerclient import exceptions
 | 
			
		||||
from freezerclient.utils import doc_from_json_file
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
logging = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionShow(ShowOne):
 | 
			
		||||
    """Show a single session"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(SessionShow, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='session_id',
 | 
			
		||||
                            help='ID of the session')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        session = self.app.client.sessions.get(parsed_args.session_id)
 | 
			
		||||
 | 
			
		||||
        if not session:
 | 
			
		||||
            raise exceptions.ApiClientException('Session not found')
 | 
			
		||||
 | 
			
		||||
        column = (
 | 
			
		||||
            'Session ID',
 | 
			
		||||
            'Description',
 | 
			
		||||
            'Status',
 | 
			
		||||
            'Jobs'
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        data = (
 | 
			
		||||
            session.get('session_id'),
 | 
			
		||||
            session.get('description'),
 | 
			
		||||
            session.get('status'),
 | 
			
		||||
            pformat(session.get('jobs'))
 | 
			
		||||
        )
 | 
			
		||||
        return column, data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionList(Lister):
 | 
			
		||||
    """List all the sessions for your user"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(SessionList, self).get_parser(prog_name)
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--limit',
 | 
			
		||||
            dest='limit',
 | 
			
		||||
            default=100,
 | 
			
		||||
            help='Specify a limit for search query',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--offset',
 | 
			
		||||
            dest='offset',
 | 
			
		||||
            default=0,
 | 
			
		||||
            help='',
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(
 | 
			
		||||
            '--search',
 | 
			
		||||
            dest='search',
 | 
			
		||||
            default='',
 | 
			
		||||
            help='Define a filter for the query',
 | 
			
		||||
        )
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        sessions = self.app.client.sessions.list_all(
 | 
			
		||||
            limit=parsed_args.limit,
 | 
			
		||||
            offset=parsed_args.offset,
 | 
			
		||||
            search=parsed_args.search
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return (('Session ID', 'Description', 'Status', '# Jobs'),
 | 
			
		||||
                ((session.get('session_id'),
 | 
			
		||||
                  session.get('description'),
 | 
			
		||||
                  session.get('status'),
 | 
			
		||||
                  len(session.get('jobs', [])),
 | 
			
		||||
                  ) for session in sessions))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionCreate(Command):
 | 
			
		||||
    """Create a session from a file"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(SessionCreate, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument('--file',
 | 
			
		||||
                            dest='file',
 | 
			
		||||
                            help='Path to json file with the job')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        session = doc_from_json_file(parsed_args.file)
 | 
			
		||||
        session_id = self.app.client.sessions.create(session)
 | 
			
		||||
        logging.info('Session {0} created'.format(session_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionAddJob(Command):
 | 
			
		||||
    """Add a job to a session"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(SessionAddJob, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument('--session-id',
 | 
			
		||||
                            dest='session_id',
 | 
			
		||||
                            help='ID of the session')
 | 
			
		||||
        parser.add_argument('--job-id',
 | 
			
		||||
                            dest='job_id',
 | 
			
		||||
                            help='ID of the job to add')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        self.app.client.sessions.add_job(parsed_args.session_id,
 | 
			
		||||
                                         parsed_args.job_id)
 | 
			
		||||
        logging.info('Job {0} added correctly to session {1}'.format(
 | 
			
		||||
            parsed_args.job_id, parsed_args.session_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionRemoveJob(Command):
 | 
			
		||||
    """Remove a job from a session"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(SessionRemoveJob, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument('--session-id',
 | 
			
		||||
                            dest='session_id',
 | 
			
		||||
                            help='ID of the session')
 | 
			
		||||
        parser.add_argument('--job-id',
 | 
			
		||||
                            dest='job_id',
 | 
			
		||||
                            help='ID of the job to add')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        try:
 | 
			
		||||
            self.app.client.sessions.remove_job(parsed_args.session_id,
 | 
			
		||||
                                                parsed_args.job_id)
 | 
			
		||||
        except Exception as error:
 | 
			
		||||
            # there is an error coming from the api when a job is removed
 | 
			
		||||
            # with the following text:
 | 
			
		||||
            # Additional properties are not allowed ('job_event' was unexpected)
 | 
			
		||||
            # but in reality the job gets removed correctly.
 | 
			
		||||
            if 'Additional properties are not allowed' in error.message:
 | 
			
		||||
                pass
 | 
			
		||||
            else:
 | 
			
		||||
                raise exceptions.ApiClientException(error.message)
 | 
			
		||||
        else:
 | 
			
		||||
            logging.info('Job {0} removed correctly from session {1}'.format(
 | 
			
		||||
                parsed_args.job_id, parsed_args.session_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionStart(Command):
 | 
			
		||||
    """Start a session"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionEnd(Command):
 | 
			
		||||
    """Stop a session"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionUpdate(Command):
 | 
			
		||||
    """Update a session from a file"""
 | 
			
		||||
    def get_parser(self, prog_name):
 | 
			
		||||
        parser = super(SessionUpdate, self).get_parser(prog_name)
 | 
			
		||||
        parser.add_argument(dest='session_id',
 | 
			
		||||
                            help='ID of the session')
 | 
			
		||||
 | 
			
		||||
        parser.add_argument(dest='file',
 | 
			
		||||
                            help='Path to json file with the session')
 | 
			
		||||
        return parser
 | 
			
		||||
 | 
			
		||||
    def take_action(self, parsed_args):
 | 
			
		||||
        session = doc_from_json_file(parsed_args.file)
 | 
			
		||||
        self.app.client.sessions.update(parsed_args.session_id, session)
 | 
			
		||||
        logging.info('Session {0} updated'.format(parsed_args.session_id))
 | 
			
		||||
							
								
								
									
										12
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
astroid<1.4.0 # breaks pylint 1.4.4
 | 
			
		||||
setuptools>=16.0
 | 
			
		||||
pbr>=1.6
 | 
			
		||||
python-keystoneclient>=1.6.0,!=1.8.0
 | 
			
		||||
 | 
			
		||||
cliff!=1.16.0,>=1.15.0 # Apache-2.0
 | 
			
		||||
oslo.utils>=3.2.0
 | 
			
		||||
oslo.i18n>=1.5.0 # Apache-2.0
 | 
			
		||||
oslo.log>=1.14.0
 | 
			
		||||
oslo.config>=3.2.0  # Apache-2.0
 | 
			
		||||
 | 
			
		||||
six>=1.9.0 # MIT
 | 
			
		||||
							
								
								
									
										49
									
								
								setup.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								setup.cfg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
[metadata]
 | 
			
		||||
name = python-freezerclient
 | 
			
		||||
summary = OpenStack Disaster Recovery API Client Library
 | 
			
		||||
description-file =
 | 
			
		||||
    README.rst
 | 
			
		||||
license = Apache License, Version 2.0
 | 
			
		||||
author = Freezer Team
 | 
			
		||||
author-email = openstack-dev@lists.openstack.org
 | 
			
		||||
home-page = https://wiki.openstack.org/wiki/Freezer
 | 
			
		||||
classifier =
 | 
			
		||||
    Programming Language :: Python
 | 
			
		||||
    Development Status :: 5 - Production/Stable
 | 
			
		||||
    Natural Language :: English
 | 
			
		||||
    Environment :: OpenStack
 | 
			
		||||
    Intended Audience :: Developers
 | 
			
		||||
    Intended Audience :: Information Technology
 | 
			
		||||
    Intended Audience :: System Administrators
 | 
			
		||||
    License :: OSI Approved :: Apache Software License
 | 
			
		||||
    Operating System :: MacOS
 | 
			
		||||
    Operating System :: POSIX :: BSD :: FreeBSD
 | 
			
		||||
    Operating System :: POSIX :: BSD :: NetBSD
 | 
			
		||||
    Operating System :: POSIX :: BSD :: OpenBSD
 | 
			
		||||
    Operating System :: POSIX :: Linux
 | 
			
		||||
    Operating System :: Microsoft :: Windows
 | 
			
		||||
    Operating System :: Unix
 | 
			
		||||
    Topic :: System :: Archiving :: Backup
 | 
			
		||||
    Topic :: System :: Archiving :: Compression
 | 
			
		||||
    Topic :: System :: Archiving
 | 
			
		||||
 | 
			
		||||
[files]
 | 
			
		||||
packages =
 | 
			
		||||
    freezerclient
 | 
			
		||||
 | 
			
		||||
[build_sphinx]
 | 
			
		||||
source-dir = doc/source
 | 
			
		||||
build-dir = doc/build
 | 
			
		||||
all_files = 1
 | 
			
		||||
 | 
			
		||||
[entry_points]
 | 
			
		||||
console_scripts =
 | 
			
		||||
    freezer = freezerclient.shell:main
 | 
			
		||||
 | 
			
		||||
[pbr]
 | 
			
		||||
# Have pbr generate the module indexes like sphinx autodoc
 | 
			
		||||
autodoc_index_modules = True
 | 
			
		||||
 | 
			
		||||
# Treat sphinx warnings as errors during the docs build; this helps us keep
 | 
			
		||||
# the documentation clean.
 | 
			
		||||
warnerrors = true
 | 
			
		||||
							
								
								
									
										28
									
								
								setup.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								setup.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
 | 
			
		||||
import setuptools
 | 
			
		||||
 | 
			
		||||
# In python < 2.7.4, a lazy loading of package `pbr` will break
 | 
			
		||||
# setuptools if some other modules registered functions in `atexit`.
 | 
			
		||||
# solution from: http://bugs.python.org/issue15881#msg170215
 | 
			
		||||
try:
 | 
			
		||||
    import multiprocessing  # noqa
 | 
			
		||||
except ImportError:
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
setuptools.setup(
 | 
			
		||||
    setup_requires=['pbr'],
 | 
			
		||||
    pbr=True)
 | 
			
		||||
							
								
								
									
										11
									
								
								test-requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								test-requirements.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
flake8>=2.2.4,<=2.4.1
 | 
			
		||||
hacking>=0.10.2,<0.11
 | 
			
		||||
coverage>=3.6
 | 
			
		||||
discover
 | 
			
		||||
mock>=1.2
 | 
			
		||||
pylint==1.4.5 # GNU GPL v2
 | 
			
		||||
python-subunit>=0.0.18
 | 
			
		||||
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 # BSD
 | 
			
		||||
oslosphinx>=2.5.0,!=3.4.0 # Apache-2.0
 | 
			
		||||
testrepository>=0.0.18
 | 
			
		||||
testtools>=1.4.0
 | 
			
		||||
							
								
								
									
										67
									
								
								tox.ini
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								tox.ini
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
[tox]
 | 
			
		||||
envlist = py27,py34,pep8,pylint,docs
 | 
			
		||||
skipsdist = True
 | 
			
		||||
 | 
			
		||||
[testenv]
 | 
			
		||||
usedevelop = True
 | 
			
		||||
deps =
 | 
			
		||||
    -r{toxinidir}/requirements.txt
 | 
			
		||||
    -r{toxinidir}/test-requirements.txt
 | 
			
		||||
 | 
			
		||||
install_command = pip install -U {opts} {packages}
 | 
			
		||||
setenv = VIRTUAL_ENV={envdir}
 | 
			
		||||
 | 
			
		||||
whitelist_externals =
 | 
			
		||||
    find
 | 
			
		||||
    coverage
 | 
			
		||||
    rm
 | 
			
		||||
 | 
			
		||||
python_files = test_*.py
 | 
			
		||||
norecursedirs  = .tox .venv
 | 
			
		||||
 | 
			
		||||
[testenv:venv]
 | 
			
		||||
commands = {posargs}
 | 
			
		||||
 | 
			
		||||
[testenv:py27]
 | 
			
		||||
basepython = python2.7
 | 
			
		||||
setenv =
 | 
			
		||||
    OS_TEST_PATH = ./freezerclient/tests/unit
 | 
			
		||||
commands =
 | 
			
		||||
    find . -type f -name "*.pyc" -delete
 | 
			
		||||
    python setup.py testr --coverage --testr-args="{posargs}"
 | 
			
		||||
    coverage report -m
 | 
			
		||||
    rm -f .coverage
 | 
			
		||||
    rm -rf .testrepository
 | 
			
		||||
 | 
			
		||||
[testenv:py34]
 | 
			
		||||
basepython = python3.4
 | 
			
		||||
setenv =
 | 
			
		||||
  OS_TEST_PATH = ./freezerclient/tests/unit
 | 
			
		||||
commands =
 | 
			
		||||
    find . -type f -name "*.pyc" -delete
 | 
			
		||||
    python setup.py testr --coverage --testr-args="{posargs}"
 | 
			
		||||
    coverage report -m
 | 
			
		||||
    rm -f .coverage
 | 
			
		||||
    rm -rf .testrepository
 | 
			
		||||
 | 
			
		||||
[testenv:docs]
 | 
			
		||||
commands =
 | 
			
		||||
  python setup.py build_sphinx
 | 
			
		||||
 | 
			
		||||
[testenv:pep8]
 | 
			
		||||
commands = flake8 freezerclient
 | 
			
		||||
 | 
			
		||||
[testenv:pylint]
 | 
			
		||||
commands = pylint --rcfile .pylintrc freezerclient
 | 
			
		||||
 | 
			
		||||
[flake8]
 | 
			
		||||
# it's not a bug that we aren't using all of hacking
 | 
			
		||||
# H102 -> apache2 license exists
 | 
			
		||||
# H103 -> license is apache
 | 
			
		||||
# H201 -> no bare excepts
 | 
			
		||||
# H501 -> don't use locals() for str formatting
 | 
			
		||||
# H903 -> \n not \r\n
 | 
			
		||||
ignore = H
 | 
			
		||||
select = H102, H103, H201, H501, H903, H201, H306, H301, H233
 | 
			
		||||
show-source = True
 | 
			
		||||
exclude = .venv,.tox,dist,doc,test,*egg,tests
 | 
			
		||||
		Reference in New Issue
	
	Block a user