Skip to content

Commit 08c8214

Browse files
authored
Merge pull request softlayer#1 from softlayer/master
Updating from upstream
2 parents a324f11 + eeabb61 commit 08c8214

27 files changed

Lines changed: 1146 additions & 20 deletions

CONTRIBUTING.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,80 @@ Code is tested and style checked with tox, you can run the tox tests individuall
2525
* create pull request
2626

2727

28+
## Documentation
2829

30+
CLI command should have a more human readable style of documentation.
31+
Manager methods should have a decent docblock describing any parameters and what the method does.
2932

33+
Docs are generated with [Sphinx](https://docs.readthedocs.io/en/latest/intro/getting-started-with-sphinx.html) and once Sphinx is setup, you can simply do
34+
35+
`make html` in the softlayer-python/docs directory, which should generate the HTML in softlayer-python/docs/_build/html for testing.
36+
37+
38+
## Unit Tests
39+
40+
All new features should be 100% code covered, and your pull request should at the very least increase total code overage.
41+
42+
### Mocks
43+
To tests results from the API, we keep mock results in SoftLayer/fixtures/<SoftLayer_Service>/ with the method name matching the variable name.
44+
45+
Any call to a service that doesn't have a fixture will result in a TransportError
46+
47+
### Overriding Fixtures
48+
49+
Adding your expected output in the fixtures file with a unique name is a good way to define a fixture that gets used frequently in a test.
50+
51+
```python
52+
from SoftLayer.fixtures import SoftLayer_Product_Package
53+
54+
def test_test(self):
55+
amock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects')
56+
amock.return_value = fixtures.SoftLayer_Product_Package.RESERVED_CAPACITY
57+
```
58+
59+
Otherwise defining it on the spot works too.
60+
```python
61+
def test_test(self):
62+
mock = self.set_mock('SoftLayer_Network_Storage', 'getObject')
63+
mock.return_value = {
64+
'billingItem': {'hourlyFlag': True, 'id': 449},
65+
}
66+
```
67+
68+
69+
### Call testing
70+
Testing your code to make sure it makes the correct API call is also very important.
71+
72+
The testing.TestCase class has a method call `assert_called_with` which is pretty handy here.
73+
74+
```python
75+
self.assert_called_with(
76+
'SoftLayer_Billing_Item', # Service
77+
'cancelItem', # Method
78+
args=(True, True, ''), # Args
79+
identifier=449, # Id
80+
mask=mock.ANY, # object Mask,
81+
filter=mock.ANY, # object Filter
82+
limit=0, # result Limit
83+
offset=0 # result Offset
84+
)
85+
```
86+
87+
Making sure a API was NOT called
88+
89+
```python
90+
self.assertEqual([], self.calls('SoftLayer_Account', 'getObject'))
91+
```
92+
93+
Making sure an API call has a specific arg, but you don't want to list out the entire API call (like with a place order test)
94+
95+
```python
96+
# Get the API Call signature
97+
order_call = self.calls('SoftLayer_Product_Order', 'placeOrder')
98+
99+
# Get the args property of that API call, which is a tuple, with the first entry being our data.
100+
order_args = getattr(order_call[0], 'args')[0]
101+
102+
# Test our specific argument value
103+
self.assertEqual(123, order_args['hostId'])
104+
```

Makefile

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# Makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line.
5+
SPHINXOPTS =
6+
SPHINXBUILD = sphinx-build
7+
PAPER =
8+
BUILDDIR = build
9+
10+
# User-friendly check for sphinx-build
11+
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12+
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13+
endif
14+
15+
# Internal variables.
16+
PAPEROPT_a4 = -D latex_paper_size=a4
17+
PAPEROPT_letter = -D latex_paper_size=letter
18+
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
19+
# the i18n builder cannot share the environment and doctrees with the others
20+
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
21+
22+
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
23+
24+
help:
25+
@echo "Please use \`make <target>' where <target> is one of"
26+
@echo " html to make standalone HTML files"
27+
@echo " dirhtml to make HTML files named index.html in directories"
28+
@echo " singlehtml to make a single large HTML file"
29+
@echo " pickle to make pickle files"
30+
@echo " json to make JSON files"
31+
@echo " htmlhelp to make HTML files and a HTML help project"
32+
@echo " qthelp to make HTML files and a qthelp project"
33+
@echo " applehelp to make an Apple Help Book"
34+
@echo " devhelp to make HTML files and a Devhelp project"
35+
@echo " epub to make an epub"
36+
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
37+
@echo " latexpdf to make LaTeX files and run them through pdflatex"
38+
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
39+
@echo " text to make text files"
40+
@echo " man to make manual pages"
41+
@echo " texinfo to make Texinfo files"
42+
@echo " info to make Texinfo files and run them through makeinfo"
43+
@echo " gettext to make PO message catalogs"
44+
@echo " changes to make an overview of all changed/added/deprecated items"
45+
@echo " xml to make Docutils-native XML files"
46+
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
47+
@echo " linkcheck to check all external links for integrity"
48+
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
49+
@echo " coverage to run coverage check of the documentation (if enabled)"
50+
51+
clean:
52+
rm -rf $(BUILDDIR)/*
53+
54+
html:
55+
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
56+
@echo
57+
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
58+
59+
dirhtml:
60+
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
61+
@echo
62+
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
63+
64+
singlehtml:
65+
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
66+
@echo
67+
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
68+
69+
pickle:
70+
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
71+
@echo
72+
@echo "Build finished; now you can process the pickle files."
73+
74+
json:
75+
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
76+
@echo
77+
@echo "Build finished; now you can process the JSON files."
78+
79+
htmlhelp:
80+
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
81+
@echo
82+
@echo "Build finished; now you can run HTML Help Workshop with the" \
83+
".hhp project file in $(BUILDDIR)/htmlhelp."
84+
85+
qthelp:
86+
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
87+
@echo
88+
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
89+
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
90+
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/softlayer-python.qhcp"
91+
@echo "To view the help file:"
92+
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/softlayer-python.qhc"
93+
94+
applehelp:
95+
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
96+
@echo
97+
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
98+
@echo "N.B. You won't be able to view it unless you put it in" \
99+
"~/Library/Documentation/Help or install it in your application" \
100+
"bundle."
101+
102+
devhelp:
103+
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
104+
@echo
105+
@echo "Build finished."
106+
@echo "To view the help file:"
107+
@echo "# mkdir -p $$HOME/.local/share/devhelp/softlayer-python"
108+
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/softlayer-python"
109+
@echo "# devhelp"
110+
111+
epub:
112+
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
113+
@echo
114+
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
115+
116+
latex:
117+
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
118+
@echo
119+
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
120+
@echo "Run \`make' in that directory to run these through (pdf)latex" \
121+
"(use \`make latexpdf' here to do that automatically)."
122+
123+
latexpdf:
124+
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
125+
@echo "Running LaTeX files through pdflatex..."
126+
$(MAKE) -C $(BUILDDIR)/latex all-pdf
127+
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
128+
129+
latexpdfja:
130+
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
131+
@echo "Running LaTeX files through platex and dvipdfmx..."
132+
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
133+
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
134+
135+
text:
136+
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
137+
@echo
138+
@echo "Build finished. The text files are in $(BUILDDIR)/text."
139+
140+
man:
141+
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
142+
@echo
143+
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
144+
145+
texinfo:
146+
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
147+
@echo
148+
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
149+
@echo "Run \`make' in that directory to run these through makeinfo" \
150+
"(use \`make info' here to do that automatically)."
151+
152+
info:
153+
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
154+
@echo "Running Texinfo files through makeinfo..."
155+
make -C $(BUILDDIR)/texinfo info
156+
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
157+
158+
gettext:
159+
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
160+
@echo
161+
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
162+
163+
changes:
164+
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
165+
@echo
166+
@echo "The overview file is in $(BUILDDIR)/changes."
167+
168+
linkcheck:
169+
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
170+
@echo
171+
@echo "Link check complete; look for any errors in the above output " \
172+
"or in $(BUILDDIR)/linkcheck/output.txt."
173+
174+
doctest:
175+
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
176+
@echo "Testing of doctests in the sources finished, look at the " \
177+
"results in $(BUILDDIR)/doctest/output.txt."
178+
179+
coverage:
180+
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
181+
@echo "Testing of coverage in the sources finished, look at the " \
182+
"results in $(BUILDDIR)/coverage/python.txt."
183+
184+
xml:
185+
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
186+
@echo
187+
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
188+
189+
pseudoxml:
190+
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
191+
@echo
192+
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

README.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,14 @@ To get the exact API call that this library makes, you can do the following.
8888
For the CLI, just use the -vvv option. If you are using the REST endpoint, this will print out a curl command that you can use, if using XML, this will print the minimal python code to make the request without the softlayer library.
8989

9090
.. code-block:: bash
91+
9192
$ slcli -vvv vs list
9293
9394
9495
If you are using the library directly in python, you can do something like this.
9596

9697
.. code-bock:: python
98+
9799
import SoftLayer
98100
import logging
99101

@@ -118,6 +120,8 @@ If you are using the library directly in python, you can do something like this.
118120
main.main()
119121
main.debug()
120122

123+
124+
121125
System Requirements
122126
-------------------
123127
* Python 2.7, 3.3, 3.4, 3.5, 3.6, or 3.7.

SoftLayer/CLI/helpers.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,20 @@ def multi_option(*param_decls, **attrs):
3030
def resolve_id(resolver, identifier, name='object'):
3131
"""Resolves a single id using a resolver function.
3232
33-
:param resolver: function that resolves ids. Should return None or a list
34-
of ids.
33+
:param resolver: function that resolves ids. Should return None or a list of ids.
3534
:param string identifier: a string identifier used to resolve ids
3635
:param string name: the object type, to be used in error messages
3736
3837
"""
38+
try:
39+
return int(identifier)
40+
except ValueError:
41+
pass # It was worth a shot
42+
3943
ids = resolver(identifier)
4044

4145
if len(ids) == 0:
42-
raise exceptions.CLIAbort("Error: Unable to find %s '%s'"
43-
% (name, identifier))
46+
raise exceptions.CLIAbort("Error: Unable to find %s '%s'" % (name, identifier))
4447

4548
if len(ids) > 1:
4649
raise exceptions.CLIAbort(

SoftLayer/CLI/routes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
('virtual:upgrade', 'SoftLayer.CLI.virt.upgrade:cli'),
3232
('virtual:credentials', 'SoftLayer.CLI.virt.credentials:cli'),
3333
('virtual:capacity', 'SoftLayer.CLI.virt.capacity:cli'),
34+
('virtual:placementgroup', 'SoftLayer.CLI.virt.placementgroup:cli'),
3435

3536
('dedicatedhost', 'SoftLayer.CLI.dedicatedhost'),
3637
('dedicatedhost:list', 'SoftLayer.CLI.dedicatedhost.list:cli'),
@@ -317,4 +318,5 @@
317318
'vm': 'virtual',
318319
'vs': 'virtual',
319320
'dh': 'dedicatedhost',
321+
'pg': 'placementgroup',
320322
}

SoftLayer/CLI/virt/create.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def _update_with_like_args(ctx, _, value):
3232
'postinstall': like_details.get('postInstallScriptUri'),
3333
'dedicated': like_details['dedicatedAccountHostOnlyFlag'],
3434
'private': like_details['privateNetworkOnlyFlag'],
35+
'placement_id': like_details.get('placementGroupId', None),
3536
}
3637

3738
like_args['flavor'] = utils.lookup(like_details,
@@ -138,6 +139,10 @@ def _parse_create_args(client, args):
138139
if args.get('host_id'):
139140
data['host_id'] = args['host_id']
140141

142+
if args.get('placementgroup'):
143+
resolver = SoftLayer.managers.PlacementManager(client).resolve_ids
144+
data['placement_id'] = helpers.resolve_id(resolver, args.get('placementgroup'), 'PlacementGroup')
145+
141146
return data
142147

143148

@@ -190,6 +195,8 @@ def _parse_create_args(client, args):
190195
help=('Security group ID to associate with the private interface'))
191196
@click.option('--wait', type=click.INT,
192197
help="Wait until VS is finished provisioning for up to X seconds before returning")
198+
@click.option('--placementgroup',
199+
help="Placement Group name or Id to order this guest on. See: slcli vs placementgroup list")
193200
@click.option('--ipv6', is_flag=True, help="Adds an IPv6 address to this guest")
194201
@environment.pass_env
195202
def cli(env, **args):

0 commit comments

Comments
 (0)